Fixes here and there...

This commit is contained in:
Themaister 2011-01-06 20:01:32 +01:00
parent eca7a59dd1
commit 86e080476a
10 changed files with 158 additions and 54 deletions

View File

@ -69,6 +69,8 @@ static const bool video_smooth = true;
// On resize and fullscreen, rendering area will stay 4:3
static const bool force_aspect = true;
#define SNES_ASPECT_RATIO (4.0/3)
////////////////
// Audio
////////////////

View File

@ -103,7 +103,7 @@ static void find_input_driver(void)
}
}
SSNES_ERR("Couldn't find any input driver named \"%s\"\n", g_settings.input.driver);
fprintf(stderr, "Available video drivers are:\n");
fprintf(stderr, "Available input drivers are:\n");
for (int i = 0; i < sizeof(input_drivers) / sizeof(input_driver_t*); i++)
fprintf(stderr, "\t%s\n", video_drivers[i]->ident);
@ -194,7 +194,7 @@ void init_video_input(void)
};
const input_driver_t *tmp = driver.input;
driver.video_data = driver.video->init(&video, &driver.input);
driver.video_data = driver.video->init(&video, &driver.input, &driver.input_data);
if ( driver.video_data == NULL )
{
@ -202,12 +202,8 @@ void init_video_input(void)
exit(1);
}
// Video driver also provides an input driver.
if ( driver.input != NULL )
{
driver.input_data = driver.video_data;
}
else // We use our configured input driver.
// Video driver didn't provide an input driver so we use configured one.
if (driver.input == NULL)
{
driver.input = tmp;
if (driver.input != NULL)

View File

@ -72,10 +72,12 @@ typedef struct input_driver
typedef struct video_driver
{
void* (*init)(video_info_t *video, const input_driver_t **input);
// Should the video driver act as an input driver as well? :)
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);
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);
void (*free)(void* data);
const char *ident;
} video_driver_t;

View File

@ -42,6 +42,7 @@ struct settings
bool vsync;
bool smooth;
bool force_aspect;
float aspect_ratio;
char cg_shader_path[256];
char bsnes_shader_path[256];
unsigned filter;

View File

@ -29,6 +29,7 @@
#define NO_SDL_GLEXT
#include <SDL/SDL.h>
#include <SDL/SDL_opengl.h>
#include "input/sdl_input.h"
#define GL_GLEXT_PROTOTYPES
#include <GL/glext.h>
@ -63,6 +64,13 @@ typedef struct gl
GLuint texture;
GLuint tex_filter;
bool should_resize;
bool quitting;
unsigned win_width;
unsigned win_height;
unsigned vp_width;
unsigned vp_height;
unsigned last_width;
unsigned last_height;
unsigned tex_w, tex_h;
@ -123,39 +131,37 @@ static inline void gl_shader_set_params(unsigned width, unsigned height,
#endif
}
#define SNES_ASPECT_RATIO (4.0/3)
static void set_viewport(int width, int height)
static void set_viewport(gl_t *gl)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
GLuint out_width = width, out_height = height;
GLuint out_width = gl->win_width, out_height = gl->win_height;
if ( keep_aspect )
{
float desired_aspect = SNES_ASPECT_RATIO;
float device_aspect = (float)width / height;
float desired_aspect = g_settings.video.aspect_ratio;
float device_aspect = (float)gl->win_width / gl->win_height;
// If the aspect ratios of screen and desired aspect ratio are sufficiently equal (floating point stuff),
// assume they are actually equal.
if ( (int)(device_aspect*1000) > (int)(desired_aspect*1000) )
{
float delta = (desired_aspect / device_aspect - 1.0) / 2.0 + 0.5;
glViewport(width * (0.5 - delta), 0, 2.0 * width * delta, height);
out_width = (int)(2.0 * width * delta);
glViewport(gl->win_width * (0.5 - delta), 0, 2.0 * gl->win_width * delta, gl->win_height);
out_width = (int)(2.0 * gl->win_width * delta);
}
else if ( (int)(device_aspect*1000) < (int)(desired_aspect*1000) )
{
float delta = (device_aspect / desired_aspect - 1.0) / 2.0 + 0.5;
glViewport(0, height * (0.5 - delta), width, 2.0 * height * delta);
out_height = (int)(2.0 * height * delta);
glViewport(0, gl->win_height * (0.5 - delta), gl->win_width, 2.0 * gl->win_height * delta);
out_height = (int)(2.0 * gl->win_height * delta);
}
else
glViewport(0, 0, width, height);
glViewport(0, 0, gl->win_width, gl->win_height);
}
else
glViewport(0, 0, width, height);
glViewport(0, 0, gl->win_width, gl->win_height);
glOrtho(0, 1, 0, 1, -1, 1);
glMatrixMode(GL_MODELVIEW);
@ -163,8 +169,8 @@ static void set_viewport(int width, int height)
gl_shader_set_proj_matrix();
gl_width = out_width;
gl_height = out_height;
gl->vp_width = out_width;
gl->vp_height = out_height;
}
static float tv_to_fps(const struct timeval *tv, const struct timeval *new_tv, int frames)
@ -202,6 +208,13 @@ static bool gl_frame(void *data, const uint16_t* frame, int width, int height, i
{
gl_t *gl = data;
if (gl->should_resize)
{
gl->should_resize = false;
SDL_SetVideoMode(gl->win_width, gl->win_height, 32, SDL_OPENGL | SDL_RESIZABLE | (g_settings.video.fullscreen ? SDL_FULLSCREEN : 0));
set_viewport(gl);
}
glClear(GL_COLOR_BUFFER_BIT);
gl_shader_set_params(width, height, gl->tex_w, gl->tex_h, gl_width, gl_height);
@ -235,6 +248,7 @@ static bool gl_frame(void *data, const uint16_t* frame, int width, int height, i
glDrawArrays(GL_QUADS, 0, 4);
show_fps();
glFlush();
SDL_GL_SwapBuffers();
return true;
@ -256,12 +270,13 @@ static void gl_set_nonblock_state(void *data, bool state)
gl_t *gl = data;
if (gl->vsync)
{
SSNES_LOG("GL VSync => %s\n", state ? "off" : "on");
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, state ? 0 : 1);
//SDL_SetVideoMode(gl->width, gl->height, 32, SDL_OPENGL | (video->fullscreen ? SDL_FULLSCREEN : 0));
//SDL_SetVideoMode(gl->win_width, gl->win_height, 32, SDL_OPENGL | SDL_RESIZABLE | (g_settings.video.fullscreen ? SDL_FULLSCREEN : 0));
}
}
static void* gl_init(video_info_t *video, const input_driver_t **input)
static void* gl_init(video_info_t *video, const input_driver_t **input, void **input_data)
{
if (SDL_Init(SDL_INIT_VIDEO) < 0)
return NULL;
@ -269,20 +284,36 @@ static void* gl_init(video_info_t *video, const input_driver_t **input)
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, video->vsync ? 1 : 0);
if (!SDL_SetVideoMode(video->width, video->height, 32, SDL_OPENGL | (video->fullscreen ? SDL_FULLSCREEN : 0)))
if (!SDL_SetVideoMode(video->width, video->height, 32, SDL_OPENGL | SDL_RESIZABLE | (video->fullscreen ? SDL_FULLSCREEN : 0)))
return NULL;
int attr = 0;
SDL_GL_GetAttribute(SDL_GL_SWAP_CONTROL, &attr);
if (attr <= 0 && video->vsync)
SSNES_WARN("GL VSync has not been enabled!\n");
attr = 0;
SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &attr);
if (attr <= 0)
SSNES_WARN("GL double buffer has not been enabled!\n");
// Remove that ugly mouse :D
SDL_ShowCursor(SDL_DISABLE);
gl_t *gl = calloc(1, sizeof(gl_t));
if ( gl == NULL )
if (!gl)
return NULL;
gl->win_width = video->width;
gl->win_height = video->height;
gl->vsync = video->vsync;
keep_aspect = video->force_aspect;
if ( video->smooth )
gl->tex_filter = GL_LINEAR;
else
gl->tex_filter = GL_NEAREST;
set_viewport(video->width, video->height);
set_viewport(gl);
glEnable(GL_TEXTURE_2D);
glDisable(GL_DITHER);
@ -323,13 +354,33 @@ static void* gl_init(video_info_t *video, const input_driver_t **input)
gl_shader_init();
*input = NULL;
// Hook up SDL input driver to get SDL_QUIT events and RESIZE.
sdl_input_t *sdl_input = input_sdl.init();
if (sdl_input)
{
sdl_input->quitting = &gl->quitting;
sdl_input->should_resize = &gl->should_resize;
sdl_input->new_width = &gl->win_width;
sdl_input->new_height = &gl->win_height;
*input = &input_sdl;
*input_data = sdl_input;
}
else
*input = NULL;
return gl;
}
static bool gl_alive(void *data)
{
gl_t *gl = data;
return !gl->quitting;
}
const video_driver_t video_gl = {
.init = gl_init,
.frame = gl_frame,
.alive = gl_alive,
.set_nonblock_state = gl_set_nonblock_state,
.free = gl_free,
.ident = "gl"

View File

@ -23,15 +23,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <libsnes.hpp>
typedef struct sdl_input
{
bool quitting;
SDL_Joystick *joysticks[2];
unsigned num_axes[2];
unsigned num_buttons[2];
unsigned num_joysticks;
} sdl_input_t;
#include "sdl_input.h"
static void* sdl_input_init(void)
{
@ -43,6 +35,8 @@ static void* sdl_input_init(void)
return NULL;
sdl->num_joysticks = SDL_NumJoysticks();
if (sdl->num_joysticks > 2)
sdl->num_joysticks = 2;
for (unsigned i = 0; i < sdl->num_joysticks; i++)
{
sdl->joysticks[i] = SDL_JoystickOpen(i);
@ -64,11 +58,6 @@ static void* sdl_input_init(void)
static bool sdl_key_pressed(void *data, int key)
{
// Check to see if we have to exit.
sdl_input_t *sdl = data;
if (sdl->quitting && key == g_settings.input.exit_emulator_key)
return true;
int num_keys;
Uint8 *keymap = SDL_GetKeyState(&num_keys);
@ -98,7 +87,7 @@ static bool sdl_is_pressed(sdl_input_t *sdl, int port_num, const struct snes_key
}
if (AXIS_POS_GET(key->joyaxis) < sdl->num_axes[port_num])
{
Sint16 val = SDL_JoystickGetAxis(sdl->joysticks[port_num], AXIS_NEG_GET(key->joyaxis));
Sint16 val = SDL_JoystickGetAxis(sdl->joysticks[port_num], AXIS_POS_GET(key->joyaxis));
float scaled = (float)val / 0x8000;
if (scaled > g_settings.input.axis_threshold)
return true;
@ -136,7 +125,7 @@ static void sdl_input_free(void *data)
{
sdl_input_t *sdl = data;
for (int i = 0; i < sdl->num_joysticks; i++)
SDL_JoystickClose(i);
SDL_JoystickClose(sdl->joysticks[i]);
free(data);
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
@ -148,14 +137,31 @@ static void sdl_input_poll(void *data)
SDL_PumpEvents();
SDL_Event event;
// Search for SDL_QUIT
sdl_input_t *sdl = data;
// Search for events...
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
switch (event.type)
{
sdl_input_t *sdl = data;
sdl->quitting = true;
break;
case SDL_QUIT:
if (sdl->quitting)
{
*sdl->quitting = true;
return;
}
break;
case SDL_VIDEORESIZE:
if (sdl->should_resize)
{
*sdl->new_width = event.resize.w;
*sdl->new_height = event.resize.h;
*sdl->should_resize = true;
}
break;
default:
break;
}
}
}

36
input/sdl_input.h Normal file
View File

@ -0,0 +1,36 @@
/* SSNES - A Super Ninteno Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __SSNES_SDL_INPUT_H
#define __SSNES_SDL_INPUT_H
#include <SDL/SDL.h>
typedef struct sdl_input
{
SDL_Joystick *joysticks[2];
unsigned num_axes[2];
unsigned num_buttons[2];
unsigned num_joysticks;
// A video driver could pre-init with the SDL driver and have it handle resizing events...
bool *quitting;
bool *should_resize;
unsigned *new_width;
unsigned *new_height;
} sdl_input_t;
#endif

View File

@ -90,6 +90,7 @@ static void set_defaults(void)
g_settings.video.vsync = vsync;
g_settings.video.smooth = video_smooth;
g_settings.video.force_aspect = force_aspect;
g_settings.video.aspect_ratio = SNES_ASPECT_RATIO;
g_settings.audio.enable = audio_enable;
g_settings.audio.out_rate = out_rate;
@ -183,6 +184,9 @@ void parse_config(void)
if (config_get_bool(conf, "video_force_aspect", &tmp_bool))
g_settings.video.force_aspect = tmp_bool;
if (config_get_double(conf, "video_aspect_ratio", &tmp_double))
g_settings.video.aspect_ratio = tmp_double;
if (config_get_string(conf, "video_cg_shader", &tmp_str))
{
strncpy(g_settings.video.cg_shader_path, tmp_str, sizeof(g_settings.video.cg_shader_path) - 1);

View File

@ -417,10 +417,10 @@ int main(int argc, char *argv[])
}
#endif
///// TODO: Modular friendly!!!
for(;;)
{
if (driver.input->key_pressed(driver.input_data, g_settings.input.exit_emulator_key))
if (driver.input->key_pressed(driver.input_data, g_settings.input.exit_emulator_key) ||
!driver.video->alive(driver.video_data))
break;
if (driver.input->key_pressed(driver.input_data, g_settings.input.save_state_key))

View File

@ -22,9 +22,12 @@
# Smoothens picture with bilinear filtering. Should be disabled if using Cg shaders.
# video_smooth = true
# Forces rendering area to stay 4:3.
# Forces rendering area to stay equal to SNES aspect ratio 4:3 or as defined in video_aspect_ratio.
# video_force_aspect = true
# A floating point value for video aspect ratio (width / height)
# video_aspect_ratio = 1.333
# Path to Cg shader. If enabled
# video_cg_shader = "/path/to/cg/shader.cg"
@ -65,6 +68,9 @@
### Input
# Input driver. Depending on video driver, it might force a different input driver.
# input_driver = sdl
# Defines axis threshold. Possible values are [0.0, 1.0]
# input_axis_threshold = 0.6