From 7f3785ecf006b0136a46b10856c5a4f6f34f434a Mon Sep 17 00:00:00 2001 From: Themaister Date: Sun, 26 Dec 2010 04:15:12 +0100 Subject: [PATCH 01/47] Uses GL subtex. --- gfx/gl.c | 50 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/gfx/gl.c b/gfx/gl.c index 75c0e16f01..a10b340ac9 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -25,6 +25,7 @@ #include "libsnes.hpp" #include #include +#include #ifdef HAVE_CG @@ -65,6 +66,11 @@ typedef struct gl #endif GLuint texture; GLuint tex_filter; + + unsigned last_width; + unsigned last_height; + unsigned tex_w, tex_h; + GLfloat tex_coords[8]; } gl_t; @@ -252,17 +258,39 @@ static bool gl_frame(void *data, const uint16_t* frame, int width, int height, i #if HAVE_CG cgGLSetParameter2f(gl->cg_video_size, width, height); - cgGLSetParameter2f(gl->cg_texture_size, width, height); + cgGLSetParameter2f(gl->cg_texture_size, gl->tex_w, gl->tex_h); cgGLSetParameter2f(gl->cg_output_size, gl_width, gl_height); cgGLSetParameter2f(gl->cg_Vvideo_size, width, height); - cgGLSetParameter2f(gl->cg_Vtexture_size, width, height); + cgGLSetParameter2f(gl->cg_Vtexture_size, gl->tex_w, gl_tex_h); cgGLSetParameter2f(gl->cg_Voutput_size, gl_width, gl_height); #endif + if (width != gl->last_width || height != gl->last_height) // res change. need to clear out texture. + { + gl->last_width = width; + gl->last_height = height; + glPixelStorei(GL_UNPACK_ROW_LENGTH, width); + uint8_t *tmp = calloc(1, gl->tex_w * gl->tex_h * sizeof(uint16_t)); + glTexSubImage2D(GL_TEXTURE_2D, + 0, 0, 0, gl->tex_w, gl->tex_h, GL_BGRA, + GL_UNSIGNED_SHORT_1_5_5_5_REV, tmp); + free(tmp); + + gl->tex_coords[0] = 0; + gl->tex_coords[1] = (GLfloat)height / gl->tex_h; + gl->tex_coords[2] = 0; + gl->tex_coords[3] = 0; + gl->tex_coords[4] = (GLfloat)width / gl->tex_w; + gl->tex_coords[5] = 0; + gl->tex_coords[6] = (GLfloat)width / gl->tex_w; + gl->tex_coords[7] = (GLfloat)height / gl->tex_h; + } + + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch >> 1); - glTexImage2D(GL_TEXTURE_2D, - 0, GL_RGBA, width, height, 0, GL_BGRA, + glTexSubImage2D(GL_TEXTURE_2D, + 0, 0, 0, width, height, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame); glDrawArrays(GL_QUADS, 0, 4); @@ -350,7 +378,19 @@ static void* gl_init(video_info_t *video, const input_driver_t **input) glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(3, GL_FLOAT, 3 * sizeof(GLfloat), vertexes); - glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), tex_coords); + + memcpy(gl->tex_coords, tex_coords, sizeof(tex_coords)); + glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), gl->tex_coords); + + gl->tex_w = 256 * video->input_scale; + gl->tex_h = 256 * video->input_scale; + uint8_t *tmp = calloc(1, gl->tex_w * gl->tex_h * sizeof(uint16_t)); + glTexImage2D(GL_TEXTURE_2D, + 0, GL_RGBA, gl->tex_w, gl->tex_h, 0, GL_BGRA, + GL_UNSIGNED_SHORT_1_5_5_5_REV, tmp); + free(tmp); + gl->last_width = gl->tex_w; + gl->last_height = gl->tex_h; #ifdef HAVE_CG gl->cgCtx = cgCreateContext(); From 809aa95042d6dde4cb4eb7e70eb6f20bd385dd54 Mon Sep 17 00:00:00 2001 From: Themaister Date: Sun, 26 Dec 2010 05:00:01 +0100 Subject: [PATCH 02/47] fix compile error --- gfx/gl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gfx/gl.c b/gfx/gl.c index a10b340ac9..e261223f37 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -262,7 +262,7 @@ static bool gl_frame(void *data, const uint16_t* frame, int width, int height, i cgGLSetParameter2f(gl->cg_output_size, gl_width, gl_height); cgGLSetParameter2f(gl->cg_Vvideo_size, width, height); - cgGLSetParameter2f(gl->cg_Vtexture_size, gl->tex_w, gl_tex_h); + cgGLSetParameter2f(gl->cg_Vtexture_size, gl->tex_w, gl->tex_h); cgGLSetParameter2f(gl->cg_Voutput_size, gl_width, gl_height); #endif From 743da9300b839b558bb912235ac0dacbe5e1b681 Mon Sep 17 00:00:00 2001 From: Themaister Date: Wed, 29 Dec 2010 14:27:44 +0100 Subject: [PATCH 03/47] Add config file API. --- config_file.c | 271 ++++++++++++++++++++++++++++++++++++++++++++++++++ config_file.h | 20 ++++ 2 files changed, 291 insertions(+) create mode 100644 config_file.c create mode 100644 config_file.h diff --git a/config_file.c b/config_file.c new file mode 100644 index 0000000000..a27e2e9e37 --- /dev/null +++ b/config_file.c @@ -0,0 +1,271 @@ +#include "config_file.h" +#include +#include +#include +#include + +struct entry_list +{ + char *key; + char *value; + struct entry_list *next; +}; + +struct config_file +{ + struct entry_list *entries; +}; + +static char *getaline(FILE *file) +{ + char *newline = malloc(8); + size_t cur_size = 8; + size_t index = 0; + + int in = getc(file); + while (in != EOF && in != '\n') + { + if (index == cur_size) + { + cur_size *= 2; + newline = realloc(newline, cur_size); + } + + newline[index++] = in; + in = getc(file); + } + return newline; +} + +static bool parse_line(struct entry_list *list, char *line) +{ + // Remove everything after comment. + char *comment = strchr(line, '#'); + if (comment) + *comment = '\0'; + + // Skips to first character. + while (isspace(*line)) + line++; + + char *key = malloc(8); + size_t cur_size = 8; + size_t index = 0; + + while (isgraph(*line)) + { + if (index == cur_size) + { + cur_size *= 2; + key = realloc(key, cur_size); + } + + key[index++] = *line++; + } + list->key = key; + + while (isspace(*line)) + line++; + + // If we don't have an equal sign here, we've got an invalid string... + if (*line != '=') + { + list->key = NULL; + free(key); + return false; + } + line++; + + while (isspace(*line)) + line++; + + // We have a full string. Read until next ". + if (*line == '"') + { + char *tok = strtok(line + 1, "\""); + if (tok == NULL) + { + list->key = NULL; + free(key); + return false; + } + list->value = strdup(tok); + } + else // We don't have that... Read till next space. + { + char *tok = strtok(line, " \t\f"); + if (tok == NULL) + { + list->key = NULL; + free(key); + return false; + } + list->value = strdup(tok); + } + + return true; +} + +static void print_config(config_file_t *conf) +{ + struct entry_list *tmp = conf->entries; + while (tmp != NULL) + { + printf("Key: \"%s\", Value: \"%s\"\n", tmp->key, tmp->value); + tmp = tmp->next; + } +} + +config_file_t *config_file_new(const char *path) +{ + FILE *file = fopen(path, "r"); + if (!file) + return NULL; + + struct config_file *conf = calloc(1, sizeof(*conf)); + if (conf == NULL) + return NULL; + + struct entry_list *tail = conf->entries; + + while (!feof(file)) + { + struct entry_list *list = calloc(1, sizeof(*list)); + char *line = getaline(file); + + if (line) + { + if (parse_line(list, line)) + { + if (conf->entries == NULL) + { + conf->entries = list; + tail = list; + } + else + { + tail->next = list; + tail = list; + } + } + free(line); + } + } + fclose(file); + + //print_config(conf); + + return conf; +} + +void config_file_free(config_file_t *conf) +{ + if (conf != NULL) + { + struct entry_list *tmp = conf->entries; + struct entry_list *old = tmp; + while (tmp != NULL) + { + free(tmp->key); + free(tmp->value); + old = tmp; + tmp = tmp->next; + free(old); + } + free(conf); + } +} + +bool config_get_double(config_file_t *conf, const char *key, double *in) +{ + struct entry_list *list = conf->entries; + + while (list != NULL) + { + if (strcmp(key, list->key) == 0) + { + *in = strtod(list->value, NULL); + return true; + } + list = list->next; + } + return false; +} + +bool config_get_int(config_file_t *conf, const char *key, int *in) +{ + struct entry_list *list = conf->entries; + + while (list != NULL) + { + if (strcmp(key, list->key) == 0) + { + *in = strtol(list->value, NULL, 0); + return true; + } + list = list->next; + } + return false; +} + +bool config_get_char(config_file_t *conf, const char *key, char *in) +{ + struct entry_list *list = conf->entries; + + while (list != NULL) + { + if (strcmp(key, list->key) == 0) + { + if (strlen(list->value) > 1) + return false; + *in = *list->value; + return true; + } + list = list->next; + } + return false; +} + +bool config_get_string(config_file_t *conf, const char *key, char **str) +{ + struct entry_list *list = conf->entries; + + while (list != NULL) + { + if (strcmp(key, list->key) == 0) + { + *str = strdup(list->value); + return true; + } + list = list->next; + } + return false; +} + +bool config_get_bool(config_file_t *conf, const char *key, bool *in) +{ + struct entry_list *list = conf->entries; + + while (list != NULL) + { + if (strcmp(key, list->key) == 0) + { + if (strcasecmp(list->value, "true") == 0) + *in = true; + else if (strcasecmp(list->value, "1") == 0) + *in = true; + else if (strcasecmp(list->value, "false") == 0) + *in = false; + else if (strcasecmp(list->value, "0") == 0) + *in = false; + else + return false; + + return true; + } + list = list->next; + } + return false; +} + + diff --git a/config_file.h b/config_file.h new file mode 100644 index 0000000000..67e083e7db --- /dev/null +++ b/config_file.h @@ -0,0 +1,20 @@ +#ifndef __CONFIG_FILE_H +#define __CONFIG_FILE_H + +#include +#include + +typedef struct config_file config_file_t; + +config_file_t *config_file_new(const char *path); +void config_file_free(config_file_t *conf); + +bool config_get_double(config_file_t *conf, const char *entry, double *in); +bool config_get_int(config_file_t *conf, const char *entry, int *in); +bool config_get_char(config_file_t *conf, const char *entry, char *in); +bool config_get_string(config_file_t *conf, const char *entry, char **in); +bool config_get_bool(config_file_t *conf, const char *entry, bool *in); + + + +#endif From 50abb14d96858e5736c018ad44a48f561385682c Mon Sep 17 00:00:00 2001 From: Themaister Date: Wed, 29 Dec 2010 17:52:53 +0100 Subject: [PATCH 04/47] Appends the terminating nul to parsing strings. --- config_file.c | 10 ++++++---- config_file.h | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/config_file.c b/config_file.c index a27e2e9e37..b489f7ba8f 100644 --- a/config_file.c +++ b/config_file.c @@ -18,7 +18,7 @@ struct config_file static char *getaline(FILE *file) { - char *newline = malloc(8); + char *newline = malloc(9); size_t cur_size = 8; size_t index = 0; @@ -28,12 +28,13 @@ static char *getaline(FILE *file) if (index == cur_size) { cur_size *= 2; - newline = realloc(newline, cur_size); + newline = realloc(newline, cur_size + 1); } newline[index++] = in; in = getc(file); } + newline[index] = '\0'; return newline; } @@ -48,7 +49,7 @@ static bool parse_line(struct entry_list *list, char *line) while (isspace(*line)) line++; - char *key = malloc(8); + char *key = malloc(9); size_t cur_size = 8; size_t index = 0; @@ -57,11 +58,12 @@ static bool parse_line(struct entry_list *list, char *line) if (index == cur_size) { cur_size *= 2; - key = realloc(key, cur_size); + key = realloc(key, cur_size + 1); } key[index++] = *line++; } + key[index] = '\0'; list->key = key; while (isspace(*line)) diff --git a/config_file.h b/config_file.h index 67e083e7db..8b0b0b71ba 100644 --- a/config_file.h +++ b/config_file.h @@ -6,13 +6,28 @@ typedef struct config_file config_file_t; +///// +// Config file format +// - # are treated as comments. Rest of the line is ignored. +// - Format is: key = value. There can be as many spaces as you like in-between. +// - Value can be wrapped inside "" for multiword strings. (foo = "hai u") + +// Loads a config file. Returns NULL if file doesn't exist. config_file_t *config_file_new(const char *path); +// Frees config file. void config_file_free(config_file_t *conf); +// All extract functions return true when value is valid and exists. Returns false otherwise. + +// Extracts a double from config file. bool config_get_double(config_file_t *conf, const char *entry, double *in); +// Extracts an int from config file. bool config_get_int(config_file_t *conf, const char *entry, int *in); +// Extracts a single char. If value consists of several chars, this is an error. bool config_get_char(config_file_t *conf, const char *entry, char *in); +// Extracts an allocated string in *in. This must be free()-d if this function succeeds. bool config_get_string(config_file_t *conf, const char *entry, char **in); +// Extracts a boolean from config. Valid boolean true are "true" and "1". Valid false are "false" and "0". Other values will be treated as an error. bool config_get_bool(config_file_t *conf, const char *entry, bool *in); From 1da09c19d6fc4f9b8a5e544308282a5c24a84c1c Mon Sep 17 00:00:00 2001 From: Themaister Date: Wed, 29 Dec 2010 17:55:28 +0100 Subject: [PATCH 05/47] move config file api --- config_file.c => conf/config_file.c | 0 config_file.h => conf/config_file.h | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename config_file.c => conf/config_file.c (100%) rename config_file.h => conf/config_file.h (100%) diff --git a/config_file.c b/conf/config_file.c similarity index 100% rename from config_file.c rename to conf/config_file.c diff --git a/config_file.h b/conf/config_file.h similarity index 100% rename from config_file.h rename to conf/config_file.h From 013234a89ab490d065803803c0859273d46568c0 Mon Sep 17 00:00:00 2001 From: Themaister Date: Wed, 29 Dec 2010 19:00:21 +0100 Subject: [PATCH 06/47] Started adding settings API. --- Makefile | 2 +- general.h | 41 ++++++++++++++-- settings.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 4 deletions(-) create mode 100644 settings.c diff --git a/Makefile b/Makefile index 94f52f093a..57bdec9ae2 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ include config.mk TARGET = ssnes DEFINES = -OBJ = ssnes.o file.o driver.o +OBJ = ssnes.o file.o driver.o conf/config_file.o settings.o libsnes = -lsnes LIBS = -lsamplerate $(libsnes) diff --git a/general.h b/general.h index 50b071add8..06093dc95a 100644 --- a/general.h +++ b/general.h @@ -21,6 +21,7 @@ #include #include +#include "driver.h" #define SSNES_LOG(msg, args...) do { \ if (verbose) \ @@ -31,8 +32,42 @@ fprintf(stderr, "SSNES [ERROR] :: " msg, ##args); \ } while(0) -extern bool verbose; -extern SRC_STATE *source; -extern bool fullscreen; +#define MAX_PLAYERS 2 +#define MAX_BINDS 14 +struct settings +{ + struct + { + float xscale; + float yscale; + unsigned fullscreen_x; + unsigned fullscreen_y; + bool vsync; + bool smooth; + bool force_aspect; + char cg_shader_path[256]; + char video_filter[64]; + } video; + + struct + { + bool enable; + unsigned out_rate; + unsigned in_rate; + char device[256]; + unsigned latency; + bool sync; + int src_quality; + } audio; + + struct + { + struct snes_keybind binds[MAX_PLAYERS][MAX_BINDS]; + } input; +}; + +void parse_config(void); + +extern struct settings g_settings; #endif diff --git a/settings.c b/settings.c new file mode 100644 index 0000000000..9cbeb7e181 --- /dev/null +++ b/settings.c @@ -0,0 +1,138 @@ +#include "general.h" +#include "conf/config_file.h" +#include "config.h" +#include + +struct settings g_settings; + +static void set_defaults(void) +{ + g_settings.video.xscale = xscale; + g_settings.video.yscale = yscale; + g_settings.video.fullscreen_x = fullscreen_x; + g_settings.video.fullscreen_y = fullscreen_y; + g_settings.video.vsync = vsync; + g_settings.video.smootn = video_smooth; + g_settings.video.force_aspect = force_aspect; + strncpy(g_settings.video.cg_shader_path, cg_shader_path, sizeof(g_settings.video.cg_shader_path) - 1); + strncpy(g_settings.video.video_filter, "foo", sizeof(g_settings.video.video_filter) - 1); + + g_settings.audio.enable = audio_enable; + g_settings.audio.out_rate = out_rate; + g_settings.audio.in_rate = in_rate; + if (audio_device) + strncpy(g_settings.audio.device, audio_device, sizeof(g_settings.audio.device)); + g_settings.audio.latency = out_latency; + g_settings.audio.sync = audio_sync; + g_settings.audio.src_quality = SAMPLERATE_QUALITY; + + assert(sizeof(g_settings.input.binds[0]) >= sizeof(snes_keybinds_1)); + assert(sizeof(g_settings.input.binds[1]) >= sizeof(snes_keybinds_2)); + memcpy(g_settings.input.binds[0], snes_keybinds_1, sizeof(snes_keybinds_1)); + memcpy(g_settings.input.binds[1], snes_keybinds_2, sizeof(snes_keybinds_2)); +} + +void parse_config(void) +{ + memset(&g_settings, 0, sizeof(struct settings)); + config_file_t *conf = NULL; + + const char *xdg = getenv("XDG_CONFIG_HOME"); + if (xdg) + { + char conf_path[strlen(xdg) + strlen("/ssnes ")]; + strcpy(conf_path, xdg); + strcat(conf_path, "/ssnes"); + conf = config_file_new(conf_path); + } + else + { + const char *home = getenv("HOME"); + + if (home) + { + char conf_path[strlen(home) + strlen("/.ssnesrc ")]; + strcpy(conf_path, xdg); + strcat(conf_path, "/.ssnesrc"); + conf = config_file_new(conf_path); + } + } + + set_defaults(); + if (conf == NULL) + return; + + int tmp_int; + double tmp_double; + bool tmp_bool; + char *tmp_str; + + // Video settings. + if (config_get_double(conf, "video_xscale", &tmp_double)) + g_settings.video.xscale = tmp_double; + + if (config_get_double(conf, "video_yscale", &tmp_double)) + g_settings.video.yscale = tmp_double; + + if (config_get_int(conf, "video_fullscreen_x", &tmp_int)) + g_settings.video.fullscreen_x = tmp_int; + + if (config_get_int(conf, "video_fullscreen_y", &tmp_int)) + g_settings.video.fullscreen_y = tmp_int; + + if (config_get_bool(conf, "video_vsync", &tmp_bool)) + g_settings.video.vsync = tmp_bool; + + if (config_get_bool(conf, "video_smooth", &tmp_bool)) + g_settings.video.smooth = tmp_bool; + + if (config_get_bool(conf, "video_force_aspect", &tmp_bool)) + g_settings.video.force_aspect = tmp_bool; + + if (config_get_string(conf, "video_cg_shader_path", &tmp_str)) + { + strncpy(g_settings.video.cg_shader_path, tmp_str, sizeof(g_settings.video.cg_shader_path) - 1); + free(tmp_str); + } + + if (config_get_string(conf, "video_video_filter", &tmp_str)) + { + strncpy(g_settings.video.video_filter, tmp_str, sizeof(g_settings.video.video_filter) - 1); + free(tmp_str); + } + + // Audio settings. + if (config_get_bool(conf, "audio_enable", &tmp_bool)) + g_settings.audio.enable = tmp_bool; + + if (config_get_int(conf, "audio_out_rate", &tmp_int)) + g_settings.audio.out_rate = tmp_int; + + if (config_get_int(conf, "audio_in_rate", &tmp_int)) + g_settings.audio.in_rate = tmp_int; + + if (config_get_string(conf, "audio_device", &tmp_str)) + { + strncpy(g_settings.audio.device, tmp_str, sizeof(g_settings.audio.device) - 1); + free(tmp_str); + } + + if (config_get_int(conf, "audio_latency", &tmp_int)) + g_settings.audio.latency = tmp_int; + + if (config_get_bool(conf, "audio_sync", &tmp_bool)) + g_settings.audio.sync = tmp_bool; + + if (config_get_int(conf, "audio_src_quality", &tmp_int)) + { + int quals[] = {SRC_ZERO_ORDER_HOLD, SRC_LINEAR, SRC_SINC_FASTEST, + SRC_SINC_MEDIUM, SRC_SINC_BEST}; + + if (tmp_int > 0 && tmp_int < 6) + g_settings.audio.src_quality = quals[tmp_int]; + } + + // TODO: Keybinds. + + config_file_free(conf); +} From 2da6a4e2cc779b6270d108a16c4cb5b4becec4c6 Mon Sep 17 00:00:00 2001 From: Themaister Date: Wed, 29 Dec 2010 19:18:37 +0100 Subject: [PATCH 07/47] More work on configs. --- Makefile | 2 +- driver.c | 21 +++++++++------------ driver.h | 2 -- general.h | 27 +++++++++++++++++++-------- settings.c | 8 ++++++-- ssnes.c | 23 +++++++++++++---------- 6 files changed, 48 insertions(+), 35 deletions(-) diff --git a/Makefile b/Makefile index 57bdec9ae2..b22fdb4cff 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,7 @@ ifeq ($(BUILD_FILTER), 1) OBJ += hqflt/snes_ntsc/snes_ntsc.o endif -CFLAGS = -Wall -O3 -std=gnu99 -Wno-unused-variable -I. $(DEFINES) +CFLAGS = -Wall -O0 -g -std=gnu99 -Wno-unused-variable -I. $(DEFINES) all: $(TARGET) diff --git a/driver.c b/driver.c index 5a4fc2f68b..9cd59a1375 100644 --- a/driver.c +++ b/driver.c @@ -37,36 +37,36 @@ void init_audio(void) { if (!audio_enable) { - audio_active = false; + g_extern.audio_active = false; return; } driver.audio_data = driver.audio->init(audio_device, out_rate, out_latency); if ( driver.audio_data == NULL ) - audio_active = false; + g_extern.audio_active = false; - if (!audio_sync && audio_active) + if (!audio_sync && g_extern.audio_active) driver.audio->set_nonblock_state(driver.audio_data, true); int err; - source = src_new(SAMPLERATE_QUALITY, 2, &err); - if (!source) - audio_active = false; + g_extern.source = src_new(SAMPLERATE_QUALITY, 2, &err); + if (!g_extern.source) + g_extern.audio_active = false; } void uninit_audio(void) { if (!audio_enable) { - audio_active = false; + g_extern.audio_active = false; return; } if ( driver.audio_data && driver.audio ) driver.audio->free(driver.audio_data); - if ( source ) - src_delete(source); + if ( g_extern.source ) + src_delete(g_extern.source); } void init_video_input(void) @@ -139,9 +139,6 @@ void uninit_video_input(void) driver.input->free(driver.input_data); } -bool video_active = true; -bool audio_active = true; - driver_t driver = { #if VIDEO_DRIVER == VIDEO_GL .video = &video_gl, diff --git a/driver.h b/driver.h index d5e215da9f..b17417012b 100644 --- a/driver.h +++ b/driver.h @@ -92,8 +92,6 @@ void uninit_video_input(void); void init_audio(void); void uninit_audio(void); -extern bool video_active; -extern bool audio_active; extern driver_t driver; //////////////////////////////////////////////// Backends diff --git a/general.h b/general.h index 06093dc95a..5f1331924f 100644 --- a/general.h +++ b/general.h @@ -23,14 +23,6 @@ #include #include "driver.h" -#define SSNES_LOG(msg, args...) do { \ - if (verbose) \ - fprintf(stderr, "SSNES: " msg, ##args); \ - } while(0) - -#define SSNES_ERR(msg, args...) do { \ - fprintf(stderr, "SSNES [ERROR] :: " msg, ##args); \ - } while(0) #define MAX_PLAYERS 2 #define MAX_BINDS 14 @@ -40,6 +32,7 @@ struct settings { float xscale; float yscale; + bool fullscreen; unsigned fullscreen_x; unsigned fullscreen_y; bool vsync; @@ -66,8 +59,26 @@ struct settings } input; }; +struct global +{ + bool verbose; + SRC_STATE *source; + bool audio_active; + bool video_active; +}; + void parse_config(void); extern struct settings g_settings; +extern struct global g_extern; + +#define SSNES_LOG(msg, args...) do { \ + if (g_extern.verbose) \ + fprintf(stderr, "SSNES: " msg, ##args); \ + } while(0) + +#define SSNES_ERR(msg, args...) do { \ + fprintf(stderr, "SSNES [ERROR] :: " msg, ##args); \ + } while(0) #endif diff --git a/settings.c b/settings.c index 9cbeb7e181..e40ffe2dc6 100644 --- a/settings.c +++ b/settings.c @@ -2,6 +2,7 @@ #include "conf/config_file.h" #include "config.h" #include +#include struct settings g_settings; @@ -9,12 +10,15 @@ static void set_defaults(void) { g_settings.video.xscale = xscale; g_settings.video.yscale = yscale; + g_settings.video.fullscreen = fullscreen; g_settings.video.fullscreen_x = fullscreen_x; g_settings.video.fullscreen_y = fullscreen_y; g_settings.video.vsync = vsync; - g_settings.video.smootn = video_smooth; + g_settings.video.smooth = video_smooth; g_settings.video.force_aspect = force_aspect; +#if HAVE_CG strncpy(g_settings.video.cg_shader_path, cg_shader_path, sizeof(g_settings.video.cg_shader_path) - 1); +#endif strncpy(g_settings.video.video_filter, "foo", sizeof(g_settings.video.video_filter) - 1); g_settings.audio.enable = audio_enable; @@ -126,7 +130,7 @@ void parse_config(void) if (config_get_int(conf, "audio_src_quality", &tmp_int)) { int quals[] = {SRC_ZERO_ORDER_HOLD, SRC_LINEAR, SRC_SINC_FASTEST, - SRC_SINC_MEDIUM, SRC_SINC_BEST}; + SRC_SINC_MEDIUM_QUALITY, SRC_SINC_BEST_QUALITY}; if (tmp_int > 0 && tmp_int < 6) g_settings.audio.src_quality = quals[tmp_int]; diff --git a/ssnes.c b/ssnes.c index 7ed812dd08..a35c3dd494 100644 --- a/ssnes.c +++ b/ssnes.c @@ -33,6 +33,10 @@ #include "hqflt/ntsc.h" #include "general.h" +struct global g_extern = { + .video_active = true, + .audio_active = true +}; // To avoid continous switching if we hold the button down, we require that the button must go from pressed, unpressed back to pressed to be able to toggle between then. @@ -46,9 +50,9 @@ void set_fast_forward_button(bool new_button_state) if (new_button_state && !old_button_state) { syncing_state = !syncing_state; - if (video_active) + if (g_extern.video_active) driver.video->set_nonblock_state(driver.video_data, syncing_state); - if (audio_active) + if (g_extern.audio_active) driver.audio->set_nonblock_state(driver.audio_data, (audio_sync) ? syncing_state : true); if (syncing_state) audio_chunk_size = AUDIO_CHUNK_SIZE_NONBLOCKING; @@ -79,7 +83,7 @@ static inline void process_frame (uint16_t * restrict out, const uint16_t * rest // Format received is 16-bit 0RRRRRGGGGGBBBBB static void video_frame(const uint16_t *data, unsigned width, unsigned height) { - if ( !video_active ) + if ( !g_extern.video_active ) return; #if VIDEO_FILTER == FILTER_HQ2X @@ -117,15 +121,14 @@ static void video_frame(const uint16_t *data, unsigned width, unsigned height) video_active = false; #else if ( !driver.video->frame(driver.video_data, data, width, height, (height == 448 || height == 478) ? 1024 : 2048) ) - video_active = false; + g_extern.video_active = false; #endif } -SRC_STATE* source = NULL; static void audio_sample(uint16_t left, uint16_t right) { - if ( !audio_active ) + if ( !g_extern.audio_active ) return; static float data[AUDIO_CHUNK_SIZE_NONBLOCKING]; @@ -148,14 +151,14 @@ static void audio_sample(uint16_t left, uint16_t right) src_data.end_of_input = 0; src_data.src_ratio = (double)out_rate / (double)in_rate; - src_process(source, &src_data); + src_process(g_extern.source, &src_data); src_float_to_short_array(outsamples, temp_outsamples, src_data.output_frames_gen * 2); if ( driver.audio->write(driver.audio_data, temp_outsamples, src_data.output_frames_gen * 4) < 0 ) { fprintf(stderr, "SSNES [ERROR]: Audio backend failed to write. Will continue without sound.\n"); - audio_active = false; + g_extern.audio_active = false; } data_ptr = 0; @@ -199,7 +202,6 @@ static void print_help(void) puts("\t-v/--verbose: Verbose logging"); } -bool fullscreen = START_FULLSCREEN; static FILE* rom_file = NULL; static char savefile_name_srm[256] = {0}; bool verbose = false; @@ -304,6 +306,7 @@ int main(int argc, char *argv[]) { snes_init(); parse_input(argc, argv); + parse_config(); void *rom_buf; ssize_t rom_len = 0; @@ -367,7 +370,7 @@ int main(int argc, char *argv[]) else if ( glfwGetKey( TOGGLE_FULLSCREEN ) ) { - fullscreen = !fullscreen; + g_settings.video.fullscreen = !g_settings.video.fullscreen; uninit_drivers(); init_drivers(); } From 80d98f765efa509489d202a3bc00cf490ed60766 Mon Sep 17 00:00:00 2001 From: Themaister Date: Wed, 29 Dec 2010 19:43:17 +0100 Subject: [PATCH 08/47] More fixes --- Makefile | 1 + conf/config_file.c | 2 +- driver.c | 33 ++++++++++++++------------- general.h | 8 +++++++ settings.c | 4 ++++ ssnes.c | 56 +++++++++++++++++++++------------------------- 6 files changed, 58 insertions(+), 46 deletions(-) diff --git a/Makefile b/Makefile index b22fdb4cff..f27a3a50c8 100644 --- a/Makefile +++ b/Makefile @@ -65,6 +65,7 @@ uninstall: $(TARGET) clean: rm -f *.o rm -f audio/*.o + rm -f conf/*.o rm -f gfx/*.o rm -f hqflt/*.o rm -f hqflt/snes_ntsc/*.o diff --git a/conf/config_file.c b/conf/config_file.c index b489f7ba8f..4041d101ae 100644 --- a/conf/config_file.c +++ b/conf/config_file.c @@ -155,7 +155,7 @@ config_file_t *config_file_new(const char *path) } fclose(file); - //print_config(conf); + print_config(conf); return conf; } diff --git a/driver.c b/driver.c index 9cd59a1375..746b6e9a4f 100644 --- a/driver.c +++ b/driver.c @@ -17,9 +17,9 @@ #include "driver.h" -#include "config.h" #include "general.h" #include +#include void init_drivers(void) { @@ -35,28 +35,28 @@ void uninit_drivers(void) void init_audio(void) { - if (!audio_enable) + if (!g_settings.audio.enable) { g_extern.audio_active = false; return; } - driver.audio_data = driver.audio->init(audio_device, out_rate, out_latency); + driver.audio_data = driver.audio->init(strlen(g_settings.audio.device) ? g_settings.audio.device : NULL, g_settings.audio.out_rate, g_settings.audio.latency); if ( driver.audio_data == NULL ) g_extern.audio_active = false; - if (!audio_sync && g_extern.audio_active) + if (!g_settings.audio.sync && g_extern.audio_active) driver.audio->set_nonblock_state(driver.audio_data, true); int err; - g_extern.source = src_new(SAMPLERATE_QUALITY, 2, &err); + g_extern.source = src_new(g_settings.audio.src_quality, 2, &err); if (!g_extern.source) g_extern.audio_active = false; } void uninit_audio(void) { - if (!audio_enable) + if (!g_settings.audio.enable) { g_extern.audio_active = false; return; @@ -74,6 +74,7 @@ void init_video_input(void) int scale; // We multiply scales with 2 to allow for hi-res games. +#if 0 #if VIDEO_FILTER == FILTER_NONE scale = 2; #elif VIDEO_FILTER == FILTER_HQ2X @@ -89,14 +90,16 @@ void init_video_input(void) #else scale = 2; #endif +#endif + scale = 2; video_info_t video = { - .width = (fullscreen) ? fullscreen_x : (296 * xscale), - .height = (fullscreen) ? fullscreen_y : (224 * yscale), - .fullscreen = fullscreen, - .vsync = vsync, - .force_aspect = force_aspect, - .smooth = video_smooth, + .width = (g_settings.video.fullscreen) ? g_settings.video.fullscreen_x : (296 * g_settings.video.xscale), + .height = (g_settings.video.fullscreen) ? g_settings.video.fullscreen_y : (224 * g_settings.video.yscale), + .fullscreen = g_settings.video.fullscreen, + .vsync = g_settings.video.vsync, + .force_aspect = g_settings.video.force_aspect, + .smooth = g_settings.video.smooth, .input_scale = scale, }; @@ -146,12 +149,12 @@ driver_t driver = { #error "Define a valid video driver in config.h" #endif -#if AUDIO_DRIVER == AUDIO_RSOUND +#if AUDIO_DRIVER == AUDIO_ALSA + .audio = &audio_alsa, +#elif AUDIO_DRIVER == AUDIO_RSOUND .audio = &audio_rsound, #elif AUDIO_DRIVER == AUDIO_OSS .audio = &audio_oss, -#elif AUDIO_DRIVER == AUDIO_ALSA - .audio = &audio_alsa, #elif AUDIO_DRIVER == AUDIO_ROAR .audio = &audio_roar, #elif AUDIO_DRIVER == AUDIO_AL diff --git a/general.h b/general.h index 5f1331924f..de00116756 100644 --- a/general.h +++ b/general.h @@ -22,6 +22,7 @@ #include #include #include "driver.h" +#include #define MAX_PLAYERS 2 @@ -56,6 +57,9 @@ struct settings struct { struct snes_keybind binds[MAX_PLAYERS][MAX_BINDS]; + int save_state_key; + int load_state_key; + int toggle_fullscreen_key; } input; }; @@ -65,6 +69,10 @@ struct global SRC_STATE *source; bool audio_active; bool video_active; + + FILE *rom_file; + char savefile_name_srm[256]; + char cg_shader_path[256]; }; void parse_config(void); diff --git a/settings.c b/settings.c index e40ffe2dc6..f430f8b031 100644 --- a/settings.c +++ b/settings.c @@ -34,6 +34,10 @@ static void set_defaults(void) assert(sizeof(g_settings.input.binds[1]) >= sizeof(snes_keybinds_2)); memcpy(g_settings.input.binds[0], snes_keybinds_1, sizeof(snes_keybinds_1)); memcpy(g_settings.input.binds[1], snes_keybinds_2, sizeof(snes_keybinds_2)); + + g_settings.input.save_state_key = SAVE_STATE_KEY; + g_settings.input.load_state_key = LOAD_STATE_KEY; + g_settings.input.toggle_fullscreen_key = TOGGLE_FULLSCREEN; } void parse_config(void) diff --git a/ssnes.c b/ssnes.c index a35c3dd494..7be025a850 100644 --- a/ssnes.c +++ b/ssnes.c @@ -24,7 +24,6 @@ #include #include #include -#include "config.h" #include "driver.h" #include "file.h" #include "hqflt/pastlib.h" @@ -53,7 +52,7 @@ void set_fast_forward_button(bool new_button_state) if (g_extern.video_active) driver.video->set_nonblock_state(driver.video_data, syncing_state); if (g_extern.audio_active) - driver.audio->set_nonblock_state(driver.audio_data, (audio_sync) ? syncing_state : true); + driver.audio->set_nonblock_state(driver.audio_data, (g_settings.audio.sync) ? syncing_state : true); if (syncing_state) audio_chunk_size = AUDIO_CHUNK_SIZE_NONBLOCKING; else @@ -86,6 +85,7 @@ static void video_frame(const uint16_t *data, unsigned width, unsigned height) if ( !g_extern.video_active ) return; +#if 0 #if VIDEO_FILTER == FILTER_HQ2X uint16_t outputHQ2x[width * height * 2 * 2]; #elif VIDEO_FILTER == FILTER_HQ4X @@ -122,8 +122,11 @@ static void video_frame(const uint16_t *data, unsigned width, unsigned height) #else if ( !driver.video->frame(driver.video_data, data, width, height, (height == 448 || height == 478) ? 1024 : 2048) ) g_extern.video_active = false; +#endif #endif + if ( !driver.video->frame(driver.video_data, data, width, height, (height == 448 || height == 478) ? 1024 : 2048) ) + g_extern.video_active = false; } static void audio_sample(uint16_t left, uint16_t right) @@ -149,7 +152,7 @@ static void audio_sample(uint16_t left, uint16_t right) src_data.input_frames = audio_chunk_size / 2; src_data.output_frames = audio_chunk_size * 8; src_data.end_of_input = 0; - src_data.src_ratio = (double)out_rate / (double)in_rate; + src_data.src_ratio = (double)g_settings.audio.out_rate / (double)g_settings.audio.in_rate; src_process(g_extern.source, &src_data); @@ -172,7 +175,7 @@ static void input_poll(void) static int16_t input_state(bool port, unsigned device, unsigned index, unsigned id) { - const struct snes_keybind *binds[] = { snes_keybinds_1, snes_keybinds_2 }; + const struct snes_keybind *binds[] = { g_settings.input.binds[0], g_settings.input.binds[1] }; return driver.input->input_state(driver.input_data, binds, port, device, index, id); } @@ -202,13 +205,6 @@ static void print_help(void) puts("\t-v/--verbose: Verbose logging"); } -static FILE* rom_file = NULL; -static char savefile_name_srm[256] = {0}; -bool verbose = false; -#ifdef HAVE_CG -char cg_shader_path[256] = DEFAULT_CG_SHADER; -#endif - static void parse_input(int argc, char *argv[]) { if (argc < 2) @@ -247,18 +243,18 @@ static void parse_input(int argc, char *argv[]) exit(0); case 's': - strncpy(savefile_name_srm, optarg, sizeof(savefile_name_srm)); - savefile_name_srm[sizeof(savefile_name_srm)-1] = '\0'; + strncpy(g_extern.savefile_name_srm, optarg, sizeof(g_extern.savefile_name_srm)); + g_extern.savefile_name_srm[sizeof(g_extern.savefile_name_srm)-1] = '\0'; break; #ifdef HAVE_CG case 'f': - strncpy(cg_shader_path, optarg, sizeof(cg_shader_path) - 1); + strncpy(g_extern.cg_shader_path, optarg, sizeof(g_extern.cg_shader_path) - 1); break; #endif case 'v': - verbose = true; + g_extern.verbose = true; break; case '?': @@ -285,16 +281,16 @@ static void parse_input(int argc, char *argv[]) snes_set_cartridge_basename(tmp); SSNES_LOG("Opening file: \"%s\"\n", argv[optind]); - rom_file = fopen(argv[optind], "rb"); - if (rom_file == NULL) + g_extern.rom_file = fopen(argv[optind], "rb"); + if (g_extern.rom_file == NULL) { SSNES_ERR("Could not open file: \"%s\"\n", optarg); exit(1); } - if (strlen(savefile_name_srm) == 0) - fill_pathname(savefile_name_srm, argv[optind], ".srm"); + if (strlen(g_extern.savefile_name_srm) == 0) + fill_pathname(g_extern.savefile_name_srm, argv[optind], ".srm"); } - else if (strlen(savefile_name_srm) == 0) + else if (strlen(g_extern.savefile_name_srm) == 0) { SSNES_ERR("Need savefile argument when reading rom from stdin.\n"); print_help(); @@ -310,18 +306,18 @@ int main(int argc, char *argv[]) void *rom_buf; ssize_t rom_len = 0; - if ((rom_len = read_file(rom_file, &rom_buf)) == -1) + if ((rom_len = read_file(g_extern.rom_file, &rom_buf)) == -1) { SSNES_ERR("Could not read ROM file.\n"); exit(1); } SSNES_LOG("ROM size: %zi bytes\n", rom_len); - if (rom_file != NULL) - fclose(rom_file); + if (g_extern.rom_file != NULL) + fclose(g_extern.rom_file); - char statefile_name[strlen(savefile_name_srm)+strlen(".state")+1]; - char savefile_name_rtc[strlen(savefile_name_srm)+strlen(".rtc")+1]; + char statefile_name[strlen(g_extern.savefile_name_srm)+strlen(".state")+1]; + char savefile_name_rtc[strlen(g_extern.savefile_name_srm)+strlen(".rtc")+1]; fill_pathname(statefile_name, argv[1], ".state"); fill_pathname(savefile_name_rtc, argv[1], ".rtc"); @@ -349,7 +345,7 @@ int main(int argc, char *argv[]) goto error; } - load_save_file(savefile_name_srm, SNES_MEMORY_CARTRIDGE_RAM); + load_save_file(g_extern.savefile_name_srm, SNES_MEMORY_CARTRIDGE_RAM); load_save_file(savefile_name_rtc, SNES_MEMORY_CARTRIDGE_RTC); ///// TODO: Modular friendly!!! @@ -360,15 +356,15 @@ int main(int argc, char *argv[]) if ( quitting ) break; - if ( glfwGetKey( SAVE_STATE_KEY )) + if ( glfwGetKey( g_settings.input.save_state_key )) { write_file(statefile_name, serial_data, serial_size); } - else if ( glfwGetKey( LOAD_STATE_KEY ) ) + else if ( glfwGetKey( g_settings.input.load_state_key ) ) load_state(statefile_name, serial_data, serial_size); - else if ( glfwGetKey( TOGGLE_FULLSCREEN ) ) + else if ( glfwGetKey( g_settings.input.toggle_fullscreen_key ) ) { g_settings.video.fullscreen = !g_settings.video.fullscreen; uninit_drivers(); @@ -378,7 +374,7 @@ int main(int argc, char *argv[]) snes_run(); } - save_file(savefile_name_srm, SNES_MEMORY_CARTRIDGE_RAM); + save_file(g_extern.savefile_name_srm, SNES_MEMORY_CARTRIDGE_RAM); save_file(savefile_name_rtc, SNES_MEMORY_CARTRIDGE_RTC); snes_unload_cartridge(); From fc126942e901b428bb666f26176429becb074c88 Mon Sep 17 00:00:00 2001 From: Themaister Date: Wed, 29 Dec 2010 20:05:57 +0100 Subject: [PATCH 09/47] Fixes... Add driver ident and remove some config.h deps. --- audio/alsa.c | 3 ++- audio/openal.c | 3 ++- audio/oss.c | 3 ++- audio/roar.c | 3 ++- audio/rsound.c | 3 ++- config.h.def | 2 +- driver.c | 29 +++++++++++++++++++++++++++++ driver.h | 6 ++++++ general.h | 5 +++++ gfx/gl.c | 12 +++++++----- settings.c | 2 +- ssnes.c | 5 ++++- 12 files changed, 63 insertions(+), 13 deletions(-) diff --git a/audio/alsa.c b/audio/alsa.c index 5dece09311..4e6145141e 100644 --- a/audio/alsa.c +++ b/audio/alsa.c @@ -190,7 +190,8 @@ const audio_driver_t audio_alsa = { .stop = __alsa_stop, .start = __alsa_start, .set_nonblock_state = __alsa_set_nonblock_state, - .free = __alsa_free + .free = __alsa_free, + .ident = "alsa" }; diff --git a/audio/openal.c b/audio/openal.c index 75826541e7..431acba814 100644 --- a/audio/openal.c +++ b/audio/openal.c @@ -233,7 +233,8 @@ const audio_driver_t audio_openal = { .stop = __al_stop, .start = __al_start, .set_nonblock_state = __al_set_nonblock_state, - .free = __al_free + .free = __al_free, + .ident = "openal" }; diff --git a/audio/oss.c b/audio/oss.c index b12ddebad1..bf451905e6 100644 --- a/audio/oss.c +++ b/audio/oss.c @@ -136,7 +136,8 @@ const audio_driver_t audio_oss = { .stop = __oss_stop, .start = __oss_start, .set_nonblock_state = __oss_set_nonblock_state, - .free = __oss_free + .free = __oss_free, + .ident = "oss" }; diff --git a/audio/roar.c b/audio/roar.c index db94f0768b..89ab744560 100644 --- a/audio/roar.c +++ b/audio/roar.c @@ -107,7 +107,8 @@ const audio_driver_t audio_roar = { .stop = __roar_stop, .start = __roar_start, .set_nonblock_state = __roar_set_nonblock_state, - .free = __roar_free + .free = __roar_free, + .ident = "roar" }; diff --git a/audio/rsound.c b/audio/rsound.c index 181f0859c8..08040c2e65 100644 --- a/audio/rsound.c +++ b/audio/rsound.c @@ -135,7 +135,8 @@ const audio_driver_t audio_rsound = { .stop = __rsd_stop, .start = __rsd_start, .set_nonblock_state = __rsd_set_nonblock_state, - .free = __rsd_free + .free = __rsd_free, + .ident = "rsound" }; diff --git a/config.h.def b/config.h.def index 859daec4bb..1fd2557d1d 100644 --- a/config.h.def +++ b/config.h.def @@ -53,7 +53,7 @@ static const float xscale = 3.0; // Real x res = 296 * xscale static const float yscale = 3.0; // Real y res = 224 * yscale // Fullscreen -#define START_FULLSCREEN false; // To start in Fullscreen or not +static const bool fullscreen = false; // To start in Fullscreen or not static const unsigned fullscreen_x = 1280; static const unsigned fullscreen_y = 720; diff --git a/driver.c b/driver.c index 746b6e9a4f..159de9737c 100644 --- a/driver.c +++ b/driver.c @@ -21,6 +21,31 @@ #include #include +static audio_driver_t audio_drivers[] = { +#ifdef HAVE_ALSA + &audio_alsa, +#endif +#ifdef HAVE_OSS + &audio_oss, +#endif +#ifdef HAVE_RSOUND + &audio_rsound, +#endif +#ifdef HAVE_AL + &audio_openal, +#endif +#ifdef HAVE_ROAR + &audio_roar, +#endif +}; + +static video_driver_t video_drivers[] = { +#ifdef HAVE_GL + &video_gl, +#endif +}; + + void init_drivers(void) { init_video_input(); @@ -142,6 +167,9 @@ void uninit_video_input(void) driver.input->free(driver.input_data); } +driver_t driver; + +#if 0 driver_t driver = { #if VIDEO_DRIVER == VIDEO_GL .video = &video_gl, @@ -163,4 +191,5 @@ driver_t driver = { #error "Define a valid audio driver in config.h" #endif }; +#endif diff --git a/driver.h b/driver.h index b17417012b..651dd3cf9b 100644 --- a/driver.h +++ b/driver.h @@ -54,14 +54,19 @@ typedef struct audio_driver bool (*start)(void* data); void (*set_nonblock_state)(void* data, bool toggle); // Should we care about blocking in audio thread? Fast forwarding. void (*free)(void* data); + const char *ident; } audio_driver_t; +#define AXIS_NEG_GET(x) ((x >> 16) & 0xFFFF) +#define AXIS_POS_GET(x) (x & 0xFFFF) +#define AXIS_NONE ((uint32_t)0xFFFFFFFFU) typedef struct input_driver { void* (*init)(void); void (*poll)(void* data); int16_t (*input_state)(void* data, const struct snes_keybind **snes_keybinds, bool port, unsigned device, unsigned index, unsigned id); void (*free)(void* data); + const char *ident; } input_driver_t; typedef struct video_driver @@ -71,6 +76,7 @@ typedef struct video_driver 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. void (*free)(void* data); + const char *ident; } video_driver_t; diff --git a/general.h b/general.h index de00116756..bd8ab93893 100644 --- a/general.h +++ b/general.h @@ -31,6 +31,7 @@ struct settings { struct { + char driver[32]; float xscale; float yscale; bool fullscreen; @@ -45,6 +46,7 @@ struct settings struct { + char driver[32]; bool enable; unsigned out_rate; unsigned in_rate; @@ -56,10 +58,12 @@ struct settings struct { + char driver[32]; struct snes_keybind binds[MAX_PLAYERS][MAX_BINDS]; int save_state_key; int load_state_key; int toggle_fullscreen_key; + float axis_threshold; } input; }; @@ -73,6 +77,7 @@ struct global FILE *rom_file; char savefile_name_srm[256]; char cg_shader_path[256]; + char config_path[256]; }; void parse_config(void); diff --git a/gfx/gl.c b/gfx/gl.c index e261223f37..93e46b6aa5 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -18,7 +18,6 @@ #define GL_GLEXT_PROTOTYPES #include "driver.h" -#include "config.h" #include #include #include @@ -26,6 +25,7 @@ #include #include #include +#include "general.h" #ifdef HAVE_CG @@ -122,9 +122,9 @@ static bool glfw_is_pressed(int port_num, const struct snes_keybind *key, unsign if (key->joyaxis != AXIS_NONE) { - if (AXIS_NEG_GET(key->joyaxis) < joypad_axes[port_num] && axes[AXIS_NEG_GET(key->joyaxis)] <= -AXIS_THRESHOLD) + if (AXIS_NEG_GET(key->joyaxis) < joypad_axes[port_num] && axes[AXIS_NEG_GET(key->joyaxis)] <= -g_settings.input.axis_threshold) return true; - if (AXIS_POS_GET(key->joyaxis) < joypad_axes[port_num] && axes[AXIS_POS_GET(key->joyaxis)] >= AXIS_THRESHOLD) + if (AXIS_POS_GET(key->joyaxis) < joypad_axes[port_num] && axes[AXIS_POS_GET(key->joyaxis)] >= g_settings.input.axis_threshold) return true; } return false; @@ -174,7 +174,8 @@ static void glfw_free_input(void *data) static const input_driver_t input_glfw = { .poll = glfw_input_poll, .input_state = glfw_input_state, - .free = glfw_free_input + .free = glfw_free_input, + .ident = "glfw" }; static void GLFWCALL resize(int width, int height) @@ -446,7 +447,8 @@ const video_driver_t video_gl = { .init = gl_init, .frame = gl_frame, .set_nonblock_state = gl_set_nonblock_state, - .free = gl_free + .free = gl_free, + .ident = "glfw" }; diff --git a/settings.c b/settings.c index f430f8b031..bbefc338bd 100644 --- a/settings.c +++ b/settings.c @@ -1,6 +1,6 @@ #include "general.h" #include "conf/config_file.h" -#include "config.h" +#include "config.h.def" #include #include diff --git a/ssnes.c b/ssnes.c index 7be025a850..c5d1cde3f8 100644 --- a/ssnes.c +++ b/ssnes.c @@ -34,7 +34,10 @@ struct global g_extern = { .video_active = true, - .audio_active = true + .audio_active = true, +#if HAVE_CG + .cg_shader_path = DEFAULT_CG_SHADER +#endif }; // To avoid continous switching if we hold the button down, we require that the button must go from pressed, unpressed back to pressed to be able to toggle between then. From 16d9abc8d4f0d992f2fafe0199c7517798a54bc3 Mon Sep 17 00:00:00 2001 From: Themaister Date: Wed, 29 Dec 2010 20:06:27 +0100 Subject: [PATCH 10/47] add config.h.def stuff. --- config.h.def | 2 -- 1 file changed, 2 deletions(-) diff --git a/config.h.def b/config.h.def index 1fd2557d1d..7a43ad9a56 100644 --- a/config.h.def +++ b/config.h.def @@ -124,8 +124,6 @@ static const bool audio_sync = true; #define AXIS_NEG(x) ((uint32_t)(x << 16) | 0xFFFF) #define AXIS_POS(x) ((uint32_t)(x) | 0xFFFF0000U) -#define AXIS_NEG_GET(x) ((x >> 16) & 0xFFFF) -#define AXIS_POS_GET(x) (x & 0xFFFF) #define AXIS_NONE ((uint32_t)0xFFFFFFFFU) // To figure out which joypad buttons to use, check jstest or similar. From 869d839eeece79a65f877c0cb314169323974827 Mon Sep 17 00:00:00 2001 From: Themaister Date: Wed, 29 Dec 2010 20:50:50 +0100 Subject: [PATCH 11/47] Should work nicely. --- Makefile | 6 ++++++ config.h.def | 4 ++-- driver.c | 35 +++++++++++++++++++++++++++++++++-- settings.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index f27a3a50c8..b1277c42c0 100644 --- a/Makefile +++ b/Makefile @@ -11,26 +11,32 @@ LIBS = -lsamplerate $(libsnes) ifeq ($(BUILD_RSOUND), 1) OBJ += audio/rsound.o LIBS += -lrsound + DEFINES += -DHAVE_RSOUND endif ifeq ($(BUILD_OSS), 1) OBJ += audio/oss.o + DEFINES += -DHAVE_OSS endif ifeq ($(BUILD_ALSA), 1) OBJ += audio/alsa.o LIBS += -lasound + DEFINES += -DHAVE_ALSA endif ifeq ($(BUILD_ROAR), 1) OBJ += audio/roar.o LIBS += -lroar + DEFINES += -DHAVE_ROAR endif ifeq ($(BUILD_AL), 1) OBJ += audio/openal.o LIBS += -lopenal + DEFINES += -DHAVE_AL endif ifeq ($(BUILD_OPENGL), 1) OBJ += gfx/gl.o LIBS += -lglfw + DEFINES += -DHAVE_GL endif ifeq ($(BUILD_CG), 1) diff --git a/config.h.def b/config.h.def index 7a43ad9a56..22b95663c6 100644 --- a/config.h.def +++ b/config.h.def @@ -40,8 +40,8 @@ //////////////////////// // Chooses which video and audio subsystem to use. Remember to update config.mk if you change these. -#define VIDEO_DRIVER VIDEO_GL -#define AUDIO_DRIVER AUDIO_ALSA +#define VIDEO_DEFAULT_DRIVER VIDEO_GL +#define AUDIO_DEFAULT_DRIVER AUDIO_ALSA //////////////// diff --git a/driver.c b/driver.c index 159de9737c..f44d858f49 100644 --- a/driver.c +++ b/driver.c @@ -21,7 +21,7 @@ #include #include -static audio_driver_t audio_drivers[] = { +static const audio_driver_t *audio_drivers[] = { #ifdef HAVE_ALSA &audio_alsa, #endif @@ -39,12 +39,39 @@ static audio_driver_t audio_drivers[] = { #endif }; -static video_driver_t video_drivers[] = { +static const video_driver_t *video_drivers[] = { #ifdef HAVE_GL &video_gl, #endif }; +static void find_audio_driver(void) +{ + for (int i = 0; i < sizeof(audio_drivers) / sizeof(audio_driver_t*); i++) + { + if (strcasecmp(g_settings.audio.driver, audio_drivers[i]->ident) == 0) + { + driver.audio = audio_drivers[i]; + return; + } + } + SSNES_ERR("Couldn't find any audio driver named \"%s\"\n", g_settings.audio.driver); + exit(1); +} + +static void find_video_driver(void) +{ + for (int i = 0; i < sizeof(video_drivers) / sizeof(video_driver_t*); i++) + { + if (strcasecmp(g_settings.video.driver, video_drivers[i]->ident) == 0) + { + driver.video = video_drivers[i]; + return; + } + } + SSNES_ERR("Couldn't find any video driver named \"%s\"\n", g_settings.video.driver); + exit(1); +} void init_drivers(void) { @@ -66,6 +93,8 @@ void init_audio(void) return; } + find_audio_driver(); + driver.audio_data = driver.audio->init(strlen(g_settings.audio.device) ? g_settings.audio.device : NULL, g_settings.audio.out_rate, g_settings.audio.latency); if ( driver.audio_data == NULL ) g_extern.audio_active = false; @@ -98,6 +127,8 @@ void init_video_input(void) { int scale; + find_video_driver(); + // We multiply scales with 2 to allow for hi-res games. #if 0 #if VIDEO_FILTER == FILTER_NONE diff --git a/settings.c b/settings.c index bbefc338bd..089369f0ed 100644 --- a/settings.c +++ b/settings.c @@ -8,6 +8,46 @@ struct settings g_settings; static void set_defaults(void) { + const char *def_video = NULL; + const char *def_audio = NULL; + + switch (VIDEO_DEFAULT_DRIVER) + { + case VIDEO_GL: + def_video = "glfw"; + break; + default: + break; + } + + switch (AUDIO_DEFAULT_DRIVER) + { + case AUDIO_RSOUND: + def_audio = "rsound"; + break; + case AUDIO_OSS: + def_audio = "oss"; + break; + case AUDIO_ALSA: + def_audio = "alsa"; + break; + case AUDIO_ROAR: + def_audio = "roar"; + break; + case AUDIO_AL: + def_audio = "openal"; + break; + default: + break; + } + + // No input atm ... It is in the GLFW driver. + + if (def_video) + strncpy(g_settings.video.driver, def_video, sizeof(g_settings.video.driver) - 1); + if (def_audio) + strncpy(g_settings.audio.driver, def_audio, sizeof(g_settings.audio.driver) - 1); + g_settings.video.xscale = xscale; g_settings.video.yscale = yscale; g_settings.video.fullscreen = fullscreen; @@ -140,6 +180,17 @@ void parse_config(void) g_settings.audio.src_quality = quals[tmp_int]; } + if (config_get_string(conf, "video_driver", &tmp_str)) + { + strncpy(g_settings.video.driver, tmp_str, sizeof(g_settings.video.driver) - 1); + free(tmp_str); + } + if (config_get_string(conf, "audio_driver", &tmp_str)) + { + strncpy(g_settings.audio.driver, tmp_str, sizeof(g_settings.audio.driver) - 1); + free(tmp_str); + } + // TODO: Keybinds. config_file_free(conf); From 61a70bba6cb2b635009812cb0ceed93862f52f9b Mon Sep 17 00:00:00 2001 From: Themaister Date: Wed, 29 Dec 2010 20:56:56 +0100 Subject: [PATCH 12/47] Error message when wrong driver. --- driver.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/driver.c b/driver.c index f44d858f49..f8b758c0a0 100644 --- a/driver.c +++ b/driver.c @@ -56,6 +56,10 @@ static void find_audio_driver(void) } } SSNES_ERR("Couldn't find any audio driver named \"%s\"\n", g_settings.audio.driver); + fprintf(stderr, "Available audio drivers are:\n"); + for (int i = 0; i < sizeof(audio_drivers) / sizeof(audio_driver_t*); i++) + fprintf(stderr, "\t%s\n", audio_drivers[i]->ident); + exit(1); } @@ -70,6 +74,10 @@ static void find_video_driver(void) } } SSNES_ERR("Couldn't find any video driver named \"%s\"\n", g_settings.video.driver); + fprintf(stderr, "Available video drivers are:\n"); + for (int i = 0; i < sizeof(video_drivers) / sizeof(video_driver_t*); i++) + fprintf(stderr, "\t%s\n", video_drivers[i]->ident); + exit(1); } From 423fe969d3318bad098eafee782b95f2cdfd74f5 Mon Sep 17 00:00:00 2001 From: Themaister Date: Wed, 29 Dec 2010 21:12:56 +0100 Subject: [PATCH 13/47] should get default Cg path... --- config.h.def | 1 - gfx/gl.c | 4 ++-- settings.c | 13 ++++++++++++- ssnes.c | 15 +++++++++------ 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/config.h.def b/config.h.def index 22b95663c6..f61d7d2a8f 100644 --- a/config.h.def +++ b/config.h.def @@ -65,7 +65,6 @@ static const bool video_smooth = true; // Path to custom Cg shader. If using custom shaders, it is recommended to disable video_smooth. #ifdef HAVE_CG -extern char cg_shader_path[]; #define DEFAULT_CG_SHADER "hqflt/cg/quad.cg" #endif diff --git a/gfx/gl.c b/gfx/gl.c index 93e46b6aa5..96c482bb1a 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -409,8 +409,8 @@ static void* gl_init(video_info_t *video, const input_driver_t **input) } cgGLSetOptimalOptions(gl->cgFProf); cgGLSetOptimalOptions(gl->cgVProf); - gl->cgFPrg = cgCreateProgramFromFile(gl->cgCtx, CG_SOURCE, cg_shader_path, gl->cgFProf, "main_fragment", 0); - gl->cgVPrg = cgCreateProgramFromFile(gl->cgCtx, CG_SOURCE, cg_shader_path, gl->cgVProf, "main_vertex", 0); + gl->cgFPrg = cgCreateProgramFromFile(gl->cgCtx, CG_SOURCE, g_settings.video.cg_shader_path, gl->cgFProf, "main_fragment", 0); + gl->cgVPrg = cgCreateProgramFromFile(gl->cgCtx, CG_SOURCE, g_settings.video.cg_shader_path, gl->cgVProf, "main_vertex", 0); if (gl->cgFPrg == NULL || gl->cgVPrg == NULL) { CGerror err = cgGetError(); diff --git a/settings.c b/settings.c index 089369f0ed..d0012c603f 100644 --- a/settings.c +++ b/settings.c @@ -57,7 +57,7 @@ static void set_defaults(void) g_settings.video.smooth = video_smooth; g_settings.video.force_aspect = force_aspect; #if HAVE_CG - strncpy(g_settings.video.cg_shader_path, cg_shader_path, sizeof(g_settings.video.cg_shader_path) - 1); + strncpy(g_settings.video.cg_shader_path, DEFAULT_CG_SHADER, sizeof(g_settings.video.cg_shader_path) - 1); #endif strncpy(g_settings.video.video_filter, "foo", sizeof(g_settings.video.video_filter) - 1); @@ -78,6 +78,7 @@ static void set_defaults(void) g_settings.input.save_state_key = SAVE_STATE_KEY; g_settings.input.load_state_key = LOAD_STATE_KEY; g_settings.input.toggle_fullscreen_key = TOGGLE_FULLSCREEN; + g_settings.input.axis_threshold = AXIS_THRESHOLD; } void parse_config(void) @@ -149,6 +150,10 @@ void parse_config(void) free(tmp_str); } + // Input Settings. + if (config_get_double(conf, "input_axis_threshold", &tmp_double)) + g_settings.input.axis_threshold = tmp_double; + // Audio settings. if (config_get_bool(conf, "audio_enable", &tmp_bool)) g_settings.audio.enable = tmp_bool; @@ -191,6 +196,12 @@ void parse_config(void) free(tmp_str); } + if (config_get_string(conf, "video_cg_shader_path", &tmp_str)) + { + strncpy(g_settings.video.cg_shader_path, tmp_str, sizeof(g_settings.video.cg_shader_path) - 1); + free(tmp_str); + } + // TODO: Keybinds. config_file_free(conf); diff --git a/ssnes.c b/ssnes.c index c5d1cde3f8..7a8b5650ad 100644 --- a/ssnes.c +++ b/ssnes.c @@ -35,9 +35,6 @@ struct global g_extern = { .video_active = true, .audio_active = true, -#if HAVE_CG - .cg_shader_path = DEFAULT_CG_SHADER -#endif }; // To avoid continous switching if we hold the button down, we require that the button must go from pressed, unpressed back to pressed to be able to toggle between then. @@ -202,6 +199,7 @@ static void print_help(void) puts("Usage: ssnes [rom file] [-h/--help | -s/--save]"); puts("\t-h/--help: Show this help message"); puts("\t-s/--save: Path for save file (*.srm). Required when rom is input from stdin"); + puts("\t-c/--config: Path for config file. Defaults to $XDG_CONFIG_HOME/ssnes"); #ifdef HAVE_CG puts("\t-f/--shader: Path to Cg shader. Will be compiled at runtime.\n"); #endif @@ -220,6 +218,7 @@ static void parse_input(int argc, char *argv[]) { "help", 0, NULL, 'h' }, { "save", 1, NULL, 's' }, { "verbose", 0, NULL, 'v' }, + { "config", 0, NULL, 'c' }, #ifdef HAVE_CG { "shader", 1, NULL, 'f' }, #endif @@ -228,9 +227,9 @@ static void parse_input(int argc, char *argv[]) int option_index = 0; #ifdef HAVE_CG - char optstring[] = "hs:vf:"; + char optstring[] = "hs:vf:c:"; #else - char optstring[] = "hs:v"; + char optstring[] = "hs:vc:"; #endif for(;;) { @@ -260,6 +259,10 @@ static void parse_input(int argc, char *argv[]) g_extern.verbose = true; break; + case 'c': + strncpy(g_extern.config_path, optarg, sizeof(g_extern.config_path) - 1); + break; + case '?': print_help(); exit(1); @@ -304,8 +307,8 @@ static void parse_input(int argc, char *argv[]) int main(int argc, char *argv[]) { snes_init(); - parse_input(argc, argv); parse_config(); + parse_input(argc, argv); void *rom_buf; ssize_t rom_len = 0; From 75d8781854ea593942e6551deb40d100f2346ba8 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 01:33:40 +0100 Subject: [PATCH 14/47] Add stuff to detect filters. --- Makefile | 1 + config.h.def | 17 ++++---- driver.c | 34 +++++++--------- general.h | 3 +- gfx/gl.c | 102 +++++++++++++++++++++++++++--------------------- hqflt/filters.h | 23 +++++++++++ settings.c | 66 +++++++++++++++++++++++-------- ssnes.c | 93 +++++++++++++++++-------------------------- 8 files changed, 189 insertions(+), 150 deletions(-) create mode 100644 hqflt/filters.h diff --git a/Makefile b/Makefile index b1277c42c0..072e048b5e 100644 --- a/Makefile +++ b/Makefile @@ -50,6 +50,7 @@ ifeq ($(BUILD_FILTER), 1) OBJ += hqflt/bleed.o OBJ += hqflt/ntsc.o OBJ += hqflt/snes_ntsc/snes_ntsc.o + DEFINES += -DHAVE_FILTER endif CFLAGS = -Wall -O0 -g -std=gnu99 -Wno-unused-variable -I. $(DEFINES) diff --git a/config.h.def b/config.h.def index f61d7d2a8f..a044335aec 100644 --- a/config.h.def +++ b/config.h.def @@ -39,7 +39,6 @@ #define AUDIO_AL 5 //////////////////////// -// Chooses which video and audio subsystem to use. Remember to update config.mk if you change these. #define VIDEO_DEFAULT_DRIVER VIDEO_GL #define AUDIO_DEFAULT_DRIVER AUDIO_ALSA @@ -63,26 +62,24 @@ static const bool vsync = true; // Smooths picture static const bool video_smooth = true; -// Path to custom Cg shader. If using custom shaders, it is recommended to disable video_smooth. -#ifdef HAVE_CG -#define DEFAULT_CG_SHADER "hqflt/cg/quad.cg" -#endif - // On resize and fullscreen, rendering area will stay 4:3 static const bool force_aspect = true; /////////// Video filters (CPU based) -#define FILTER_NONE 0 +#ifdef HAVE_FILTER #define FILTER_HQ2X 1 #define FILTER_HQ4X 2 #define FILTER_GRAYSCALE 3 #define FILTER_BLEED 4 #define FILTER_NTSC 5 +#define FILTER_HQ2X_STR "hq2x" +#define FILTER_HQ4X_STR "hq4x" +#define FILTER_GRAYSCALE_STR "grayscale" +#define FILTER_BLEED_STR "bleed" +#define FILTER_NTSC_STR "ntsc" +#endif //////////////////////// -// If you change this to something other than FILTER_NONE, make sure that you build the filter module in config.mk. -#define VIDEO_FILTER FILTER_NONE - //////////////// // Audio diff --git a/driver.c b/driver.c index f8b758c0a0..6e03733a04 100644 --- a/driver.c +++ b/driver.c @@ -133,29 +133,25 @@ void uninit_audio(void) void init_video_input(void) { - int scale; + int scale = 2; find_video_driver(); // We multiply scales with 2 to allow for hi-res games. -#if 0 -#if VIDEO_FILTER == FILTER_NONE - scale = 2; -#elif VIDEO_FILTER == FILTER_HQ2X - scale = 4; -#elif VIDEO_FILTER == FILTER_HQ4X - scale = 8; -#elif VIDEO_FILTER == FILTER_NTSC - scale = 8; -#elif VIDEO_FILTER == FILTER_GRAYSCALE - scale = 2; -#elif VIDEO_FILTER == FILTER_BLEED - scale = 2; -#else - scale = 2; +#if HAVE_FILTER + switch (g_settings.video.filter) + { + case FILTER_HQ2X: + scale = 4; + break; + case FILTER_HQ4X: + case FILTER_NTSC: + scale = 8; + break; + default: + break; + } #endif -#endif - scale = 2; video_info_t video = { .width = (g_settings.video.fullscreen) ? g_settings.video.fullscreen_x : (296 * g_settings.video.xscale), @@ -168,7 +164,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); if ( driver.video_data == NULL ) { diff --git a/general.h b/general.h index bd8ab93893..3b86a831cd 100644 --- a/general.h +++ b/general.h @@ -41,7 +41,7 @@ struct settings bool smooth; bool force_aspect; char cg_shader_path[256]; - char video_filter[64]; + unsigned filter; } video; struct @@ -76,7 +76,6 @@ struct global FILE *rom_file; char savefile_name_srm[256]; - char cg_shader_path[256]; char config_path[256]; }; diff --git a/gfx/gl.c b/gfx/gl.c index 96c482bb1a..da29fb4f9e 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -50,6 +50,7 @@ static const GLfloat tex_coords[] = { static bool keep_aspect = true; #ifdef HAVE_CG static CGparameter cg_mvp_matrix; +static bool cg_active = false; #endif static GLuint gl_width = 0, gl_height = 0; typedef struct gl @@ -214,7 +215,8 @@ static void GLFWCALL resize(int width, int height) glMatrixMode(GL_MODELVIEW); glLoadIdentity(); #ifdef HAVE_CG - cgGLSetStateMatrixParameter(cg_mvp_matrix, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); + if (cg_active) + cgGLSetStateMatrixParameter(cg_mvp_matrix, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); #endif gl_width = out_width; gl_height = out_height; @@ -258,13 +260,16 @@ static bool gl_frame(void *data, const uint16_t* frame, int width, int height, i glClear(GL_COLOR_BUFFER_BIT); #if HAVE_CG - cgGLSetParameter2f(gl->cg_video_size, width, height); - cgGLSetParameter2f(gl->cg_texture_size, gl->tex_w, gl->tex_h); - cgGLSetParameter2f(gl->cg_output_size, gl_width, gl_height); + if (cg_active) + { + cgGLSetParameter2f(gl->cg_video_size, width, height); + cgGLSetParameter2f(gl->cg_texture_size, gl->tex_w, gl->tex_h); + cgGLSetParameter2f(gl->cg_output_size, gl_width, gl_height); - cgGLSetParameter2f(gl->cg_Vvideo_size, width, height); - cgGLSetParameter2f(gl->cg_Vtexture_size, gl->tex_w, gl->tex_h); - cgGLSetParameter2f(gl->cg_Voutput_size, gl_width, gl_height); + cgGLSetParameter2f(gl->cg_Vvideo_size, width, height); + cgGLSetParameter2f(gl->cg_Vtexture_size, gl->tex_w, gl->tex_h); + cgGLSetParameter2f(gl->cg_Voutput_size, gl_width, gl_height); + } #endif if (width != gl->last_width || height != gl->last_height) // res change. need to clear out texture. @@ -305,7 +310,8 @@ static void gl_free(void *data) { gl_t *gl = data; #ifdef HAVE_CG - cgDestroyContext(gl->cgCtx); + if (cg_active) + cgDestroyContext(gl->cgCtx); #endif glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); @@ -327,7 +333,7 @@ static void gl_set_nonblock_state(void *data, bool state) static void* gl_init(video_info_t *video, const input_driver_t **input) { - gl_t *gl = malloc(sizeof(gl_t)); + gl_t *gl = calloc(1, sizeof(gl_t)); if ( gl == NULL ) return NULL; @@ -394,44 +400,50 @@ static void* gl_init(video_info_t *video, const input_driver_t **input) gl->last_height = gl->tex_h; #ifdef HAVE_CG - gl->cgCtx = cgCreateContext(); - if (gl->cgCtx == NULL) + cg_active = false; + if (strlen(g_settings.video.cg_shader_path) > 0) { - fprintf(stderr, "Failed to create Cg context\n"); - goto error; - } - gl->cgFProf = cgGLGetLatestProfile(CG_GL_FRAGMENT); - gl->cgVProf = cgGLGetLatestProfile(CG_GL_VERTEX); - if (gl->cgFProf == CG_PROFILE_UNKNOWN || gl->cgVProf == CG_PROFILE_UNKNOWN) - { - fprintf(stderr, "Invalid profile type\n"); - goto error; - } - cgGLSetOptimalOptions(gl->cgFProf); - cgGLSetOptimalOptions(gl->cgVProf); - gl->cgFPrg = cgCreateProgramFromFile(gl->cgCtx, CG_SOURCE, g_settings.video.cg_shader_path, gl->cgFProf, "main_fragment", 0); - gl->cgVPrg = cgCreateProgramFromFile(gl->cgCtx, CG_SOURCE, g_settings.video.cg_shader_path, gl->cgVProf, "main_vertex", 0); - if (gl->cgFPrg == NULL || gl->cgVPrg == NULL) - { - CGerror err = cgGetError(); - fprintf(stderr, "CG error: %s\n", cgGetErrorString(err)); - goto error; - } - cgGLLoadProgram(gl->cgFPrg); - cgGLLoadProgram(gl->cgVPrg); - cgGLEnableProfile(gl->cgFProf); - cgGLEnableProfile(gl->cgVProf); - cgGLBindProgram(gl->cgFPrg); - cgGLBindProgram(gl->cgVPrg); + gl->cgCtx = cgCreateContext(); + if (gl->cgCtx == NULL) + { + fprintf(stderr, "Failed to create Cg context\n"); + goto error; + } + gl->cgFProf = cgGLGetLatestProfile(CG_GL_FRAGMENT); + gl->cgVProf = cgGLGetLatestProfile(CG_GL_VERTEX); + if (gl->cgFProf == CG_PROFILE_UNKNOWN || gl->cgVProf == CG_PROFILE_UNKNOWN) + { + fprintf(stderr, "Invalid profile type\n"); + goto error; + } + cgGLSetOptimalOptions(gl->cgFProf); + cgGLSetOptimalOptions(gl->cgVProf); + puts(g_settings.video.cg_shader_path); + gl->cgFPrg = cgCreateProgramFromFile(gl->cgCtx, CG_SOURCE, g_settings.video.cg_shader_path, gl->cgFProf, "main_fragment", 0); + gl->cgVPrg = cgCreateProgramFromFile(gl->cgCtx, CG_SOURCE, g_settings.video.cg_shader_path, gl->cgVProf, "main_vertex", 0); + if (gl->cgFPrg == NULL || gl->cgVPrg == NULL) + { + CGerror err = cgGetError(); + fprintf(stderr, "CG error: %s\n", cgGetErrorString(err)); + goto error; + } + cgGLLoadProgram(gl->cgFPrg); + cgGLLoadProgram(gl->cgVPrg); + cgGLEnableProfile(gl->cgFProf); + cgGLEnableProfile(gl->cgVProf); + cgGLBindProgram(gl->cgFPrg); + cgGLBindProgram(gl->cgVPrg); - gl->cg_video_size = cgGetNamedParameter(gl->cgFPrg, "IN.video_size"); - gl->cg_texture_size = cgGetNamedParameter(gl->cgFPrg, "IN.texture_size"); - gl->cg_output_size = cgGetNamedParameter(gl->cgFPrg, "IN.output_size"); - gl->cg_Vvideo_size = cgGetNamedParameter(gl->cgVPrg, "IN.video_size"); - gl->cg_Vtexture_size = cgGetNamedParameter(gl->cgVPrg, "IN.texture_size"); - gl->cg_Voutput_size = cgGetNamedParameter(gl->cgVPrg, "IN.output_size"); - cg_mvp_matrix = cgGetNamedParameter(gl->cgVPrg, "modelViewProj"); - cgGLSetStateMatrixParameter(cg_mvp_matrix, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); + gl->cg_video_size = cgGetNamedParameter(gl->cgFPrg, "IN.video_size"); + gl->cg_texture_size = cgGetNamedParameter(gl->cgFPrg, "IN.texture_size"); + gl->cg_output_size = cgGetNamedParameter(gl->cgFPrg, "IN.output_size"); + gl->cg_Vvideo_size = cgGetNamedParameter(gl->cgVPrg, "IN.video_size"); + gl->cg_Vtexture_size = cgGetNamedParameter(gl->cgVPrg, "IN.texture_size"); + gl->cg_Voutput_size = cgGetNamedParameter(gl->cgVPrg, "IN.output_size"); + cg_mvp_matrix = cgGetNamedParameter(gl->cgVPrg, "modelViewProj"); + cgGLSetStateMatrixParameter(cg_mvp_matrix, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); + cg_active = true; + } #endif *input = &input_glfw; diff --git a/hqflt/filters.h b/hqflt/filters.h new file mode 100644 index 0000000000..e379695352 --- /dev/null +++ b/hqflt/filters.h @@ -0,0 +1,23 @@ +#ifndef __FILTERS_H +#define __FILTERS_H + +#ifdef HAVE_FILTER + +#include "pastlib.h" +#include "grayscale.h" +#include "bleed.h" +#include "ntsc.h" + +#define FILTER_HQ2X 1 +#define FILTER_HQ4X 2 +#define FILTER_GRAYSCALE 3 +#define FILTER_BLEED 4 +#define FILTER_NTSC 5 +#define FILTER_HQ2X_STR "hq2x" +#define FILTER_HQ4X_STR "hq4x" +#define FILTER_GRAYSCALE_STR "grayscale" +#define FILTER_BLEED_STR "bleed" +#define FILTER_NTSC_STR "ntsc" +#endif + +#endif diff --git a/settings.c b/settings.c index d0012c603f..5c3b0fb40f 100644 --- a/settings.c +++ b/settings.c @@ -56,10 +56,6 @@ static void set_defaults(void) g_settings.video.vsync = vsync; g_settings.video.smooth = video_smooth; g_settings.video.force_aspect = force_aspect; -#if HAVE_CG - strncpy(g_settings.video.cg_shader_path, DEFAULT_CG_SHADER, sizeof(g_settings.video.cg_shader_path) - 1); -#endif - strncpy(g_settings.video.video_filter, "foo", sizeof(g_settings.video.video_filter) - 1); g_settings.audio.enable = audio_enable; g_settings.audio.out_rate = out_rate; @@ -86,25 +82,35 @@ void parse_config(void) memset(&g_settings, 0, sizeof(struct settings)); config_file_t *conf = NULL; - const char *xdg = getenv("XDG_CONFIG_HOME"); - if (xdg) + if (strlen(g_extern.config_path) > 0) { - char conf_path[strlen(xdg) + strlen("/ssnes ")]; - strcpy(conf_path, xdg); - strcat(conf_path, "/ssnes"); - conf = config_file_new(conf_path); + conf = config_file_new(g_extern.config_path); + if (!conf) + { + SSNES_ERR("Couldn't find config at path: \"%s\"\n", g_extern.config_path); + exit(1); + } } else { + const char *xdg = getenv("XDG_CONFIG_HOME"); const char *home = getenv("HOME"); - - if (home) + if (xdg) + { + char conf_path[strlen(xdg) + strlen("/ssnes ")]; + strcpy(conf_path, xdg); + strcat(conf_path, "/ssnes"); + conf = config_file_new(conf_path); + } + else if (home) { char conf_path[strlen(home) + strlen("/.ssnesrc ")]; strcpy(conf_path, xdg); strcat(conf_path, "/.ssnesrc"); conf = config_file_new(conf_path); } + else // Try /etc/ssnes.conf as a final test ... + conf = config_file_new("/etc/ssnes.conf"); } set_defaults(); @@ -138,17 +144,43 @@ void parse_config(void) if (config_get_bool(conf, "video_force_aspect", &tmp_bool)) g_settings.video.force_aspect = tmp_bool; - if (config_get_string(conf, "video_cg_shader_path", &tmp_str)) + 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); free(tmp_str); } - if (config_get_string(conf, "video_video_filter", &tmp_str)) +#ifdef HAVE_FILTER + if (config_get_string(conf, "video_filter", &tmp_str)) { - strncpy(g_settings.video.video_filter, tmp_str, sizeof(g_settings.video.video_filter) - 1); + unsigned filter = 0; + if (strcasecmp(FILTER_HQ2X_STR, tmp_str) == 0) + filter = FILTER_HQ2X; + else if (strcasecmp(FILTER_HQ4X_STR, tmp_str) == 0) + filter = FILTER_HQ4X; + else if (strcasecmp(FILTER_GRAYSCALE_STR, tmp_str) == 0) + filter = FILTER_GRAYSCALE; + else if (strcasecmp(FILTER_BLEED_STR, tmp_str) == 0) + filter = FILTER_BLEED; + else if (strcasecmp(FILTER_NTSC_STR, tmp_str) == 0) + filter = FILTER_NTSC; + else + { + SSNES_ERR( + "Invalid filter... Valid filters are:\n" + "\t%s\n" + "\t%s\n" + "\t%s\n" + "\t%s\n" + "\t%s\n", + FILTER_HQ2X_STR, FILTER_HQ4X_STR, FILTER_GRAYSCALE_STR, + FILTER_BLEED, FILTER_NTSC); + exit(1); + } + free(tmp_str); } +#endif // Input Settings. if (config_get_double(conf, "input_axis_threshold", &tmp_double)) @@ -178,8 +210,8 @@ void parse_config(void) if (config_get_int(conf, "audio_src_quality", &tmp_int)) { - int quals[] = {SRC_ZERO_ORDER_HOLD, SRC_LINEAR, SRC_SINC_FASTEST, - SRC_SINC_MEDIUM_QUALITY, SRC_SINC_BEST_QUALITY}; + int quals[] = { SRC_ZERO_ORDER_HOLD, SRC_LINEAR, SRC_SINC_FASTEST, + SRC_SINC_MEDIUM_QUALITY, SRC_SINC_BEST_QUALITY }; if (tmp_int > 0 && tmp_int < 6) g_settings.audio.src_quality = quals[tmp_int]; diff --git a/ssnes.c b/ssnes.c index 7a8b5650ad..eebbe6ca81 100644 --- a/ssnes.c +++ b/ssnes.c @@ -26,10 +26,7 @@ #include #include "driver.h" #include "file.h" -#include "hqflt/pastlib.h" -#include "hqflt/grayscale.h" -#include "hqflt/bleed.h" -#include "hqflt/ntsc.h" +#include "hqflt/filters.h" #include "general.h" struct global g_extern = { @@ -61,7 +58,7 @@ void set_fast_forward_button(bool new_button_state) old_button_state = new_button_state; } -#if VIDEO_FILTER != FILTER_NONE +#ifdef HAVE_FILTER static inline void process_frame (uint16_t * restrict out, const uint16_t * restrict in, unsigned width, unsigned height) { int pitch = 1024; @@ -85,48 +82,46 @@ static void video_frame(const uint16_t *data, unsigned width, unsigned height) if ( !g_extern.video_active ) return; -#if 0 -#if VIDEO_FILTER == FILTER_HQ2X - uint16_t outputHQ2x[width * height * 2 * 2]; -#elif VIDEO_FILTER == FILTER_HQ4X - uint16_t outputHQ4x[width * height * 4 * 4]; -#elif VIDEO_FILTER == FILTER_NTSC - uint16_t output_ntsc[SNES_NTSC_OUT_WIDTH(width) * height]; -#endif - -#if VIDEO_FILTER != FILTER_NONE +#ifdef HAVE_FILTER + uint16_t output_filter[width * height * 4 * 4]; uint16_t output[width * height]; process_frame(output, data, width, height); -#endif -#if VIDEO_FILTER == FILTER_HQ2X - ProcessHQ2x(output, outputHQ2x); - if ( !driver.video->frame(driver.video_data, outputHQ2x, width << 1, height << 1, width << 2) ) - video_active = false; -#elif VIDEO_FILTER == FILTER_HQ4X - ProcessHQ4x(output, outputHQ4x); - if ( !driver.video->frame(driver.video_data, outputHQ4x, width << 2, height << 2, width << 3) ) - video_active = false; -#elif VIDEO_FILTER == FILTER_GRAYSCALE - grayscale_filter(output, width, height); - if ( !driver.video->frame(driver.video_data, output, width, height, width << 1) ) - video_active = false; -#elif VIDEO_FILTER == FILTER_BLEED - bleed_filter(output, width, height); - if ( !driver.video->frame(driver.video_data, output, width, height, width << 1) ) - video_active = false; -#elif VIDEO_FILTER == FILTER_NTSC - ntsc_filter(output_ntsc, output, width, height); - if ( !driver.video->frame(driver.video_data, output_ntsc, SNES_NTSC_OUT_WIDTH(width), height, SNES_NTSC_OUT_WIDTH(width) << 1) ) - video_active = false; + switch (g_settings.video.filter) + { + case FILTER_HQ2X: + ProcessHQ2x(output, output_filter); + if ( !driver.video->frame(driver.video_data, output_filter, width << 1, height << 1, width << 2) ) + 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) ) + video_active = false; + break; + case FILTER_GRAYSCALE: + grayscale_filter(output, width, height); + if ( !driver.video->frame(driver.video_data, output, width, height, width << 1) ) + video_active = false; + break; + case FILTER_BLEED: + bleed_filter(output, width, height); + if ( !driver.video->frame(driver.video_data, output, width, height, width << 1) ) + 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) ) + video_active = false; + break; + default: + if ( !driver.video->frame(driver.video_data, data, width, height, (height == 448 || height == 478) ? 1024 : 2048) ) + g_extern.video_active = false; + } #else if ( !driver.video->frame(driver.video_data, data, width, height, (height == 448 || height == 478) ? 1024 : 2048) ) g_extern.video_active = false; #endif -#endif - - if ( !driver.video->frame(driver.video_data, data, width, height, (height == 448 || height == 478) ? 1024 : 2048) ) - g_extern.video_active = false; } static void audio_sample(uint16_t left, uint16_t right) @@ -200,9 +195,6 @@ static void print_help(void) puts("\t-h/--help: Show this help message"); puts("\t-s/--save: Path for save file (*.srm). Required when rom is input from stdin"); puts("\t-c/--config: Path for config file. Defaults to $XDG_CONFIG_HOME/ssnes"); -#ifdef HAVE_CG - puts("\t-f/--shader: Path to Cg shader. Will be compiled at runtime.\n"); -#endif puts("\t-v/--verbose: Verbose logging"); } @@ -219,18 +211,11 @@ static void parse_input(int argc, char *argv[]) { "save", 1, NULL, 's' }, { "verbose", 0, NULL, 'v' }, { "config", 0, NULL, 'c' }, -#ifdef HAVE_CG - { "shader", 1, NULL, 'f' }, -#endif { NULL, 0, NULL, 0 } }; int option_index = 0; -#ifdef HAVE_CG - char optstring[] = "hs:vf:c:"; -#else char optstring[] = "hs:vc:"; -#endif for(;;) { int c = getopt_long(argc, argv, optstring, opts, &option_index); @@ -249,12 +234,6 @@ static void parse_input(int argc, char *argv[]) g_extern.savefile_name_srm[sizeof(g_extern.savefile_name_srm)-1] = '\0'; break; -#ifdef HAVE_CG - case 'f': - strncpy(g_extern.cg_shader_path, optarg, sizeof(g_extern.cg_shader_path) - 1); - break; -#endif - case 'v': g_extern.verbose = true; break; @@ -307,8 +286,8 @@ static void parse_input(int argc, char *argv[]) int main(int argc, char *argv[]) { snes_init(); - parse_config(); parse_input(argc, argv); + parse_config(); void *rom_buf; ssize_t rom_len = 0; From 8e1b1e8c0538bd78ef6edfd2c807fa3e77391b62 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 01:38:20 +0100 Subject: [PATCH 15/47] Logs config file with verbose options. --- conf/config_file.c | 4 +++- driver.c | 1 + settings.c | 4 +++- ssnes.c | 10 +++++----- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/conf/config_file.c b/conf/config_file.c index 4041d101ae..588d465e05 100644 --- a/conf/config_file.c +++ b/conf/config_file.c @@ -3,6 +3,7 @@ #include #include #include +#include "general.h" struct entry_list { @@ -155,7 +156,8 @@ config_file_t *config_file_new(const char *path) } fclose(file); - print_config(conf); + if (g_extern.verbose) + print_config(conf); return conf; } diff --git a/driver.c b/driver.c index 6e03733a04..425519fd92 100644 --- a/driver.c +++ b/driver.c @@ -20,6 +20,7 @@ #include "general.h" #include #include +#include "hqflt/filters.h" static const audio_driver_t *audio_drivers[] = { #ifdef HAVE_ALSA diff --git a/settings.c b/settings.c index 5c3b0fb40f..06f1519cbb 100644 --- a/settings.c +++ b/settings.c @@ -3,6 +3,7 @@ #include "config.h.def" #include #include +#include "hqflt/filters.h" struct settings g_settings; @@ -174,11 +175,12 @@ void parse_config(void) "\t%s\n" "\t%s\n", FILTER_HQ2X_STR, FILTER_HQ4X_STR, FILTER_GRAYSCALE_STR, - FILTER_BLEED, FILTER_NTSC); + FILTER_BLEED_STR, FILTER_NTSC_STR); exit(1); } free(tmp_str); + g_settings.video.filter = filter; } #endif diff --git a/ssnes.c b/ssnes.c index eebbe6ca81..247f55e3e2 100644 --- a/ssnes.c +++ b/ssnes.c @@ -92,27 +92,27 @@ 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) ) - video_active = false; + 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) ) - video_active = false; + 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) ) - video_active = false; + 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) ) - video_active = false; + 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) ) - video_active = false; + g_extern.video_active = false; break; default: if ( !driver.video->frame(driver.video_data, data, width, height, (height == 448 || height == 478) ? 1024 : 2048) ) From c09798018efa6890a2ad31336bcc5c732c0bc3e3 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 01:39:13 +0100 Subject: [PATCH 16/47] Move .h.def to .def.h --- config.h.def => config.def.h | 0 settings.c | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename config.h.def => config.def.h (100%) diff --git a/config.h.def b/config.def.h similarity index 100% rename from config.h.def rename to config.def.h diff --git a/settings.c b/settings.c index 06f1519cbb..d853e3e395 100644 --- a/settings.c +++ b/settings.c @@ -1,6 +1,6 @@ #include "general.h" #include "conf/config_file.h" -#include "config.h.def" +#include "config.def.h" #include #include #include "hqflt/filters.h" From 51e08c3fd1ed9539b5d0e37310fe02e5493113a8 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 01:40:35 +0100 Subject: [PATCH 17/47] Change cflags --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 072e048b5e..3e7bbbb008 100644 --- a/Makefile +++ b/Makefile @@ -53,7 +53,7 @@ ifeq ($(BUILD_FILTER), 1) DEFINES += -DHAVE_FILTER endif -CFLAGS = -Wall -O0 -g -std=gnu99 -Wno-unused-variable -I. $(DEFINES) +CFLAGS = -Wall -O3 -std=gnu99 -Wno-unused-variable -I. $(DEFINES) all: $(TARGET) From 5a8fe271995a82c9ea21753ef928ea353334d7ed Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 01:42:10 +0100 Subject: [PATCH 18/47] Remove filters from config.def.h --- config.def.h | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/config.def.h b/config.def.h index a044335aec..8db9455dcd 100644 --- a/config.def.h +++ b/config.def.h @@ -65,22 +65,6 @@ static const bool video_smooth = true; // On resize and fullscreen, rendering area will stay 4:3 static const bool force_aspect = true; -/////////// Video filters (CPU based) -#ifdef HAVE_FILTER -#define FILTER_HQ2X 1 -#define FILTER_HQ4X 2 -#define FILTER_GRAYSCALE 3 -#define FILTER_BLEED 4 -#define FILTER_NTSC 5 -#define FILTER_HQ2X_STR "hq2x" -#define FILTER_HQ4X_STR "hq4x" -#define FILTER_GRAYSCALE_STR "grayscale" -#define FILTER_BLEED_STR "bleed" -#define FILTER_NTSC_STR "ntsc" -#endif -//////////////////////// - - //////////////// // Audio //////////////// From 0d770e45fa1fff234abf56246ec90ed3df447696 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 01:42:46 +0100 Subject: [PATCH 19/47] remove uneeded flag --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3e7bbbb008..7d009c6cc2 100644 --- a/Makefile +++ b/Makefile @@ -53,7 +53,7 @@ ifeq ($(BUILD_FILTER), 1) DEFINES += -DHAVE_FILTER endif -CFLAGS = -Wall -O3 -std=gnu99 -Wno-unused-variable -I. $(DEFINES) +CFLAGS = -Wall -O3 -std=gnu99 -I. $(DEFINES) all: $(TARGET) From eca313bf9cc846fe33377c3085834edc06e38f7b Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 01:50:37 +0100 Subject: [PATCH 20/47] Add licensing info --- conf/config_file.c | 18 ++++++++++++++++++ conf/config_file.h | 18 ++++++++++++++++++ hqflt/filters.h | 18 ++++++++++++++++++ settings.c | 17 +++++++++++++++++ 4 files changed, 71 insertions(+) diff --git a/conf/config_file.c b/conf/config_file.c index 588d465e05..441256f9cd 100644 --- a/conf/config_file.c +++ b/conf/config_file.c @@ -1,3 +1,21 @@ +/* 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 . + */ + + #include "config_file.h" #include #include diff --git a/conf/config_file.h b/conf/config_file.h index 8b0b0b71ba..1992127564 100644 --- a/conf/config_file.h +++ b/conf/config_file.h @@ -1,3 +1,21 @@ +/* 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 . + */ + + #ifndef __CONFIG_FILE_H #define __CONFIG_FILE_H diff --git a/hqflt/filters.h b/hqflt/filters.h index e379695352..e375b09f41 100644 --- a/hqflt/filters.h +++ b/hqflt/filters.h @@ -1,3 +1,21 @@ +/* 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 . + */ + + #ifndef __FILTERS_H #define __FILTERS_H diff --git a/settings.c b/settings.c index d853e3e395..b131d24381 100644 --- a/settings.c +++ b/settings.c @@ -1,3 +1,20 @@ +/* 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 . + */ + #include "general.h" #include "conf/config_file.h" #include "config.def.h" From e65d9f349de5734bac065c779703e74fdf744860 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 02:52:02 +0100 Subject: [PATCH 21/47] Add quickbuild. --- configure | 13 ++ qb/conf.comp.sh | 2 + qb/config.libs.sh | 24 ++++ qb/config.params.sh | 17 +++ qb/qb.comp.sh | 68 ++++++++++ qb/qb.libs.sh | 313 ++++++++++++++++++++++++++++++++++++++++++++ qb/qb.params.sh | 149 +++++++++++++++++++++ 7 files changed, 586 insertions(+) create mode 100755 configure create mode 100644 qb/conf.comp.sh create mode 100644 qb/config.libs.sh create mode 100644 qb/config.params.sh create mode 100644 qb/qb.comp.sh create mode 100644 qb/qb.libs.sh create mode 100644 qb/qb.params.sh diff --git a/configure b/configure new file mode 100755 index 0000000000..d50a2b8eae --- /dev/null +++ b/configure @@ -0,0 +1,13 @@ +#!/bin/sh + +echo "" + +. qb/config.params.sh + +parse_input "$@" + +. qb/qb.comp.sh +. qb/config.libs.sh + + + diff --git a/qb/conf.comp.sh b/qb/conf.comp.sh new file mode 100644 index 0000000000..cd894adfb6 --- /dev/null +++ b/qb/conf.comp.sh @@ -0,0 +1,2 @@ +USE_LANG_C="yes" +USE_LANG_CXX="yes" diff --git a/qb/config.libs.sh b/qb/config.libs.sh new file mode 100644 index 0000000000..16de364dbc --- /dev/null +++ b/qb/config.libs.sh @@ -0,0 +1,24 @@ +. qb/qb.libs.sh + +check_switch_c C99 -std=gnu99 +check_critical C99 "Cannot find C99 compatible compiler." + +check_lib_cxx SNES $LIBSNES snes_init -ldl +check_critical SNES "Cannot find libsnes." + +check_lib ALSA -lasound snd_pcm_open +check_header OSS sys/soundcard.h +check_lib AL -lopenal alcOpenDevice +check_lib RSOUND -lrsound rsd_init +check_lib ROAR -lroar roar_vs_new + +check_lib GLFW -lglfw glfwInit +check_critical GLFW "Cannot find GLFW library." + +check_lib SRC -lsamplerate src_callback_new + +# Creates config.mk. +VARS="ALSA OSS AL RSOUND ROAR GLFW FILTERS" +create_config_make config.mk $VARS +create_config_header config.h $VARS + diff --git a/qb/config.params.sh b/qb/config.params.sh new file mode 100644 index 0000000000..e3c8e271ac --- /dev/null +++ b/qb/config.params.sh @@ -0,0 +1,17 @@ +. qb/qb.params.sh + +PACKAGE_NAME=ssnes +PACKAGE_VERSION=0.1 + +# Adds a command line opt to ./configure --help +# $1: Variable (HAVE_ALSA, HAVE_OSS, etc) +# $2: Comment +# $3: Default arg. auto implies that HAVE_ALSA will be set according to library checks later on. +add_command_line_string LIBSNES "libsnes library used" "-lsnes" +add_command_line_enable FILTERS "Disable CPU filter support" yes +add_command_line_enable CG "Enable CG shader support" auto +add_command_line_enable ALSA "Enable ALSA support" auto +add_command_line_enable OSS "Enable OSS support" auto +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 diff --git a/qb/qb.comp.sh b/qb/qb.comp.sh new file mode 100644 index 0000000000..12c75a6074 --- /dev/null +++ b/qb/qb.comp.sh @@ -0,0 +1,68 @@ +. qb/conf.comp.sh + +TEMP_C=.tmp.c +TEMP_CXX=.tmp.cxx +TEMP_EXE=.tmp + +echo -n "Checking operating system ... " +OS="Win32" # whatever ;D +unamestr="`uname -o`" +if [ ! -z "`echo $unamestr | grep -i Linux`" ]; then + OS="Linux" +elif [ ! -z "`echo $unamestr | grep -i Darwin`" ]; then + OS="Darwin" +elif [ ! -z "`echo $unamestr | grep -i BSD`" ]; then + OS="BSD" +elif [ ! -z "`echo $unamestr | grep -i NT`" ]; then + OS="Cygwin" +fi + +echo $OS + + +# Checking for working C compiler +if [ "$USE_LANG_C" = yes ]; then + echo "Checking for working C compiler ..." + if [ -z $CC ]; then + CC=`which gcc cc 2> /dev/null | grep ^/ | head -n 1` + fi + if [ -z $CC ]; then + echo "Could not find C compiler in path. Exiting ..." + exit 1 + fi + + echo -n "Checking if $CC is a suitable compiler ... " + answer=no + echo "#include " > $TEMP_C + echo "int main(void) { puts(\"Hai world!\"); return 0; }" >> $TEMP_C + $CC -o $TEMP_EXE $TEMP_C 2>/dev/null >/dev/null && answer=yes + echo $answer + + rm -rf $TEMP_C $TEMP_EXE + + [ $answer = no ] && echo "Can't find suitable C compiler. Exiting ..." && exit 1 +fi + +# Checking for working C++ compiler +if [ "$USE_LANG_CXX" = "yes" ]; then + echo "Checking for working C++ compiler ..." + if [ -z $CXX ]; then + CXX=`which g++ c++ 2> /dev/null | grep ^/ | head -n 1` + fi + if [ -z $CXX ]; then + echo "Could not find C compiler in path. Exiting ..." + exit 1 + fi + + echo -n "Checking if $CXX is a suitable compiler ... " + answer=no + echo "#include " > $TEMP_CXX + echo "int main() { std::cout << \"Hai guise\" << std::endl; return 0; }" >> $TEMP_CXX + $CXX -o $TEMP_EXE $TEMP_CXX 2>/dev/null >/dev/null && answer=yes + echo $answer + + rm -rf $TEMP_CXX $TEMP_EXE + + [ $answer = no ] && echo "Can't find suitable C++ compiler. Exiting ..." && exit 1 +fi + diff --git a/qb/qb.libs.sh b/qb/qb.libs.sh new file mode 100644 index 0000000000..30a13f2219 --- /dev/null +++ b/qb/qb.libs.sh @@ -0,0 +1,313 @@ + +PKG_CONF_PATH="" +PKG_CONF_USED="" +CONFIG_DEFINES="" +MAKEFILE_DEFINES="" +INCLUDE_DIRS="" +LIBRARY_DIRS="" +[ -z "$PREFIX" ] && PREFIX="/usr/local" + +add_define_header() +{ + CONFIG_DEFINES="$CONFIG_DEFINES:@$1@$2@:" +} + +add_define_make() +{ + MAKEFILE_DEFINES="$MAKEFILE_DEFINES:@$1@$2@:" +} + +add_include_dirs() +{ + while [ ! -z "$1" ] + do + INCLUDE_DIRS="$INCLUDE_DIRS -I$1" + shift + done +} + +add_library_dirs() +{ + while [ ! -z "$1" ] + do + LIBRARY_DIRS="$LIBRARY_DIRS -L$1" + shift + done +} + +check_lib() +{ + tmpval="HAVE_$1" + eval tmpval=\$$tmpval + [ "$tmpval" = "no" ] && return 0 + + echo -n "Checking function $3 in $2 ... " + echo "void $3(void); int main(void) { $3(); return 0; }" > $TEMP_C + + + eval HAVE_$1=no + answer=no + + extralibs="$4" + + $CC -o $TEMP_EXE $TEMP_C $INCLUDE_DIRS $LIBRARY_DIRS $extralibs $2 2>/dev/null >/dev/null && answer=yes && eval HAVE_$1=yes + + echo $answer + + rm -rf $TEMP_C $TEMP_EXE + if [ "$tmpval" = "yes" ] && [ "$answer" = "no" ]; then + echo "Forced to build with library $2, but cannot locate. Exiting ..." + exit 1 + fi +} + +check_lib_cxx() +{ + tmpval="HAVE_$1" + eval tmpval=\$$tmpval + [ "$tmpval" = "no" ] && return 0 + + echo -n "Checking function $3 in $2 ... " + echo "extern \"C\" { void $3(void); } int main() { $3(); }" > $TEMP_CXX + + eval HAVE_$1=no + answer=no + + extralibs="$4" + + $CXX -o $TEMP_EXE $TEMP_CXX $INCLUDE_DIRS $LIBRARY_DIRS $extralibs $2 2>/dev/null >/dev/null && answer=yes && eval HAVE_$1=yes + + echo $answer + + rm -rf $TEMP_CXX $TEMP_EXE + if [ "$tmpval" = "yes" ] && [ "$answer" = "no" ]; then + echo "Forced to build with library $2, but cannot locate. Exiting ..." + exit 1 + fi +} + +locate_pkg_conf() +{ + echo -n "Checking for pkg-config ... " + PKG_CONF_PATH="`which pkg-config | grep ^/ | head -n1`" + if [ -z $PKG_CONF_PATH ]; then + echo "not found" + echo "Cannot locate pkg-config. Exiting ..." + exit 1 + fi + echo "$PKG_CONF_PATH" +} + +check_pkgconf() +{ + [ -z "$PKG_CONF_PATH" ] && locate_pkg_conf + + tmpval="HAVE_$1" + eval tmpval=\$$tmpval + [ "$tmpval" = "no" ] && return 0 + + echo -n "Checking presence of package $2 ... " + eval HAVE_$1=no + eval $1_CFLAGS="" + eval $1_LIBS="" + answer=no + minver=0.0 + [ ! -z $3 ] && minver=$3 + pkg-config --atleast-version=$minver --exists "$2" && eval HAVE_$1=yes && eval $1_CFLAGS='"`pkg-config $2 --cflags`"' && eval $1_LIBS='"`pkg-config $2 --libs`"' && answer=yes + echo $answer + + PKG_CONF_USED="$PKG_CONF_USED $1" + + if [ "$tmpval" = "yes" ] && [ "$answer" = "no" ]; then + echo "Forced to build with package $2, but cannot locate. Exiting ..." + exit 1 + fi +} + +check_header() +{ + tmpval="HAVE_$1" + eval tmpval=\$$tmpval + [ "$tmpval" = "no" ] && return 0 + + echo -n "Checking presence of header file $2 ... " + echo "#include<$2>" > $TEMP_C + echo "int main(void) { return 0; }" >> $TEMP_C + eval HAVE_$1=no + answer=no + + $CC -o $TEMP_EXE $TEMP_C $INCLUDE_DIRS 2>/dev/null >/dev/null && answer=yes && eval HAVE_$1=yes + + echo $answer + + rm -rf $TEMP_C $TEMP_EXE + if [ "$tmpval" = "yes" ] && [ "$answer" = "no" ]; then + echo "Build assumed that $2 exists, but cannot locate. Exiting ..." + exit 1 + fi +} + +check_switch_c() +{ + echo -n "Checking for availability of switch $2 in $CC ... " + if [ -z "$CC" ]; then + echo "No C compiler, cannot check ..." + exit 1 + fi + echo "int main(void) { return 0; }" > $TEMP_C + eval HAVE_$1=no + answer=no + $CC -o $TEMP_EXE $TEMP_C $2 2>/dev/null >/dev/null && answer=yes && eval HAVE_$1=yes + + echo $answer + + rm -rf $TEMP_C $TEMP_EXE +} + +check_switch_cxx() +{ + echo -n "Checking for availability of switch $2 in $CXX ... " + if [ -z "$CXX" ]; then + echo "No C++ compiler, cannot check ..." + exit 1 + fi + echo "int main() { return 0; }" > $TEMP_CXX + eval HAVE_$1=no + answer=no + $CXX -o $TEMP_EXE $TEMP_CXX $2 2>/dev/null >/dev/null && answer=yes && eval HAVE_$1=yes + + echo $answer + + rm -rf $TEMP_CXX $TEMP_EXE +} + +check_critical() +{ + val=HAVE_$1 + eval val=\$$val + if [ "$val" != "yes" ]; then + echo "$2" + exit 1 + fi +} + +output_define_header() +{ + arg1="`echo $2 | sed 's|^@\([^@]*\)@\([^@]*\)@$|\1|'`" + arg2="`echo $2 | sed 's|^@\([^@]*\)@\([^@]*\)@$|\2|'`" + + echo "#define $arg1 $arg2" >> "$outfile" +} + +create_config_header() +{ + outfile="$1" + shift + + echo "Creating config header: $outfile" + + name="`echo __$outfile | sed 's|[\./]|_|g' | tr '[a-z]' '[A-Z]'`" + echo "#ifndef $name" > "$outfile" + echo "#define $name" >> "$outfile" + echo "" >> "$outfile" + echo "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >> "$outfile" + echo "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >> "$outfile" + + while [ ! -z "$1" ] + do + tmpval="HAVE_$1" + eval tmpval=\$$tmpval + if [ "$tmpval" = "yes" ]; then + echo "#define HAVE_$1 1" >> "$outfile" + elif [ "$tmpval" = "no" ]; then + echo "/* #undef HAVE_$1 */" >> "$outfile" + fi + + shift + done + + echo "" >> "$outfile" + + tmpdefs="$CONFIG_DEFINES" + while [ ! -z "$tmpdefs" ] + do + subdefs="`echo $tmpdefs | sed 's|^:\(@[^@]*@[^@]*@\):.*$|\1|'`" + tmpdefs="`echo $tmpdefs | sed 's|^\W*$||'`" + tmpdefs="`echo $tmpdefs | sed 's|^:\(@[^@]*@[^@]*@\):||'`" + output_define_header "$outfile" "$subdefs" + done + + echo "#endif" >> "$outfile" +} + +output_define_make() +{ + arg1="`echo $2 | sed 's|^@\([^@]*\)@\([^@]*\)@$|\1|'`" + arg2="`echo $2 | sed 's|^@\([^@]*\)@\([^@]*\)@$|\2|'`" + + echo "$arg1 = $arg2" >> "$outfile" +} + +create_config_make() +{ + + outfile="$1" + shift + + echo "Creating make config: $outfile" + + rm -rf "$outfile" + touch "$outfile" + if [ "$USE_LANG_C" = "yes" ]; then + echo "CC = $CC" >> "$outfile" + echo "CFLAGS = $CFLAGS" >> "$outfile" + fi + if [ "$USE_LANG_CXX" = "yes" ]; then + echo "CXX = $CXX" >> "$outfile" + echo "CXXFLAGS = $CXXFLAGS" >> "$outfile" + fi + echo "LDFLAGS = $LDFLAGS" >> "$outfile" + echo "INCLUDE_DIRS = $INCLUDE_DIRS" >> "$outfile" + echo "LIBRARY_DIRS = $LIBRARY_DIRS" >> "$outfile" + echo "PACKAGE_NAME = $PACKAGE_NAME" >> "$outfile" + echo "PACKAGE_VERSION = $PACKAGE_VERSION" >> "$outfile" + echo "PREFIX = $PREFIX" >> "$outfile" + + while [ ! -z "$1" ] + do + tmpval="HAVE_$1" + eval tmpval=\$$tmpval + if [ $tmpval = yes ]; then + echo "HAVE_$1 = 1" >> "$outfile" + elif [ $tmpval = no ]; then + echo "HAVE_$1 = 0" >> "$outfile" + fi + + if [ ! -z "`echo $PKG_CONF_USED | grep $1`" ]; then + tmpval="$1_CFLAGS" + eval tmpval=\$$tmpval + echo "$1_CFLAGS = $tmpval" >> "$outfile" + + tmpval="$1_LIBS" + eval tmpval=\$$tmpval + echo "$1_LIBS = $tmpval" >> "$outfile" + fi + + + shift + done + + echo "" >> "$outfile" + + tmpdefs="$MAKEFILE_DEFINES" + while [ ! -z "$tmpdefs" ] + do + subdefs="`echo $tmpdefs | sed 's|^:\(@[^@]*@[^@]*@\):.*$|\1|'`" + tmpdefs="`echo $tmpdefs | sed 's|^\W*$||'`" + tmpdefs="`echo $tmpdefs | sed 's|^:\(@[^@]*@[^@]*@\):||'`" + output_define_make "$outfile" "$subdefs" + done + +} + + diff --git a/qb/qb.params.sh b/qb/qb.params.sh new file mode 100644 index 0000000000..74ad6645fa --- /dev/null +++ b/qb/qb.params.sh @@ -0,0 +1,149 @@ +COMMAND_LINE_OPTS_ENABLE="" + +add_command_line_enable() +{ + COMMAND_LINE_OPTS_ENABLE="$COMMAND_LINE_OPTS_ENABLE:\"$1\" \"$2\" \"$3\":" + eval HAVE_$1=$3 +} + +add_command_line_string() +{ + COMMAND_LINE_OPTS_STRINGS="$COMMAND_LINE_OPTS_STRINGS:\"$1\" \"$2\" \"$3\":" + eval $1=$3 +} + +## lvl. 43 regex dragon awaits thee. +print_help() +{ + echo "====================" + echo " Quickbuild script" + echo "====================" + echo "Package: $PACKAGE_NAME" + echo "Version: $PACKAGE_VERSION" + echo "" + echo "General environment variables:" + echo "CC: C compiler" + echo "CFLAGS: C compiler flags" + echo "CXX: C++ compiler" + echo "CXXFLAGS: C++ compiler flags" + echo "LDFLAGS: Linker flags" + echo "" + echo "General options:" + echo "--prefix=\$path: Install path prefix" + echo "--help: Show this help" + echo "" + echo "Custom options:" + + tmpopts="$COMMAND_LINE_OPTS_ENABLE" + while [ ! -z "$tmpopts" ] + do + subopts="`echo $tmpopts | sed 's|^:"\([^"]*\)"."\([^"]*\)"."\([^"]*\)":.*$|"\1":"\2":"\3"|'`" + tmpopts="`echo $tmpopts | sed 's|^\W*$||'`" + tmpopts="`echo $tmpopts | sed 's|^:"[^"]*"."[^"]*"."[^"]*":||'`" + print_sub_opt "$subopts" + done + + echo "" + + tmpopts="$COMMAND_LINE_OPTS_STRINGS" + while [ ! -z "$tmpopts" ] + do + subopts="`echo $tmpopts | sed 's|^:"\([^"]*\)"."\([^"]*\)"."\([^"]*\)":.*$|"\1":"\2":"\3"|'`" + tmpopts="`echo $tmpopts | sed 's|^\W*$||'`" + tmpopts="`echo $tmpopts | sed 's|^:"[^"]*"."[^"]*"."[^"]*":||'`" + print_sub_str_opt "$subopts" + done +} + +print_sub_opt() +{ + arg1="`echo $1 | sed 's|^"\([^"]*\)":"\([^"]*\)":"\([^"]*\)"$|\1|'`" + arg2="`echo $1 | sed 's|^"\([^"]*\)":"\([^"]*\)":"\([^"]*\)"$|\2|'`" + arg3="`echo $1 | sed 's|^"\([^"]*\)":"\([^"]*\)":"\([^"]*\)"$|\3|'`" + + lowertext="`echo $arg1 | tr '[A-Z]' '[a-z]'`" + + if [ "$arg3" = "auto" ]; then + echo -n "--enable-$lowertext: " + echo $arg2 + echo "--disable-$lowertext" + elif [ "$arg3" = "yes" ]; then + echo "--disable-$lowertext: $arg2" + elif [ "$arg3" = "no" ]; then + echo "--enable-$lowertext: $arg2" + fi +} + +print_sub_str_opt() +{ + arg1="`echo $1 | sed 's|^"\([^"]*\)":"\([^"]*\)":"\([^"]*\)"$|\1|'`" + arg2="`echo $1 | sed 's|^"\([^"]*\)":"\([^"]*\)":"\([^"]*\)"$|\2|'`" + arg3="`echo $1 | sed 's|^"\([^"]*\)":"\([^"]*\)":"\([^"]*\)"$|\3|'`" + + lowertext="`echo $arg1 | tr '[A-Z]' '[a-z]'`" + + echo "--with-$lowertext: $arg2 (Defaults: $arg3)" +} + +parse_input() +{ + ### Parse stuff :V + + while [ ! -z "$1" ] + do + prefix="`echo $1 | sed -e 's|^--prefix=\(\S\S*\)$|\1|' -e 's|\(\S\S*\)/|\1|'`" + + if [ "$prefix" != "$1" ]; then + PREFIX="$prefix" + shift + continue + fi + + case "$1" in + + --enable-*) + enable=`echo $1 | sed 's|^--enable-||'` + if [ -z "`echo $COMMAND_LINE_OPTS_ENABLE | grep -i $enable`" ]; then + print_help + exit 1 + fi + eval HAVE_`echo $enable | tr '[a-z]' '[A-Z]'`=yes + ;; + + --disable-*) + disable=`echo $1 | sed 's|^--disable-||'` + if [ -z "`echo $COMMAND_LINE_OPTS_ENABLE | grep -i $disable`" ]; then + print_help + exit 1 + fi + eval HAVE_`echo $disable | tr '[a-z]' '[A-Z]'`=no + ;; + + --with-*) + arg="`echo $1 | sed 's|^--with-\S\S*=||'`" + with=`echo $1 | sed 's|^--with-\(\S\S*\)=.*$|\1|'` + if [ -z "`echo $COMMAND_LINE_OPTS_STRINGS | grep -i $with`" ]; then + print_help + exit 1 + fi + eval "`echo $with | tr '[a-z]' '[A-Z]'`=\"$arg\"" + ;; + + + -h|--help) + print_help + exit 0 + ;; + *) + print_help + exit 1 + ;; + + esac + + shift + + done +} + + From 57a5c55ca3e442fe1660d275de3b8e91c2f2182e Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 02:56:56 +0100 Subject: [PATCH 22/47] update makefile --- Makefile | 34 ++++++++++++++-------------------- qb/config.libs.sh | 1 + 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/Makefile b/Makefile index 7d009c6cc2..7777d418d6 100644 --- a/Makefile +++ b/Makefile @@ -2,60 +2,54 @@ include config.mk TARGET = ssnes -DEFINES = OBJ = ssnes.o file.o driver.o conf/config_file.o settings.o -libsnes = -lsnes LIBS = -lsamplerate $(libsnes) -ifeq ($(BUILD_RSOUND), 1) +ifeq ($(HAVE_RSOUND), 1) OBJ += audio/rsound.o LIBS += -lrsound - DEFINES += -DHAVE_RSOUND endif -ifeq ($(BUILD_OSS), 1) +ifeq ($(HAVE_OSS), 1) OBJ += audio/oss.o - DEFINES += -DHAVE_OSS endif -ifeq ($(BUILD_ALSA), 1) +ifeq ($(HAVE_ALSA), 1) OBJ += audio/alsa.o LIBS += -lasound - DEFINES += -DHAVE_ALSA endif -ifeq ($(BUILD_ROAR), 1) +ifeq ($(HAVE_ROAR), 1) OBJ += audio/roar.o LIBS += -lroar - DEFINES += -DHAVE_ROAR endif -ifeq ($(BUILD_AL), 1) +ifeq ($(HAVE_AL), 1) OBJ += audio/openal.o LIBS += -lopenal - DEFINES += -DHAVE_AL endif -ifeq ($(BUILD_OPENGL), 1) +ifeq ($(HAVE_OPENGL), 1) OBJ += gfx/gl.o LIBS += -lglfw - DEFINES += -DHAVE_GL endif -ifeq ($(BUILD_CG), 1) +ifeq ($(HAVE_CG), 1) LIBS += -lCg -lCgGL - DEFINES += -DHAVE_CG endif -ifeq ($(BUILD_FILTER), 1) +ifeq ($(HAVE_FILTER), 1) OBJ += hqflt/hq.o OBJ += hqflt/grayscale.o OBJ += hqflt/bleed.o OBJ += hqflt/ntsc.o OBJ += hqflt/snes_ntsc/snes_ntsc.o - DEFINES += -DHAVE_FILTER endif -CFLAGS = -Wall -O3 -std=gnu99 -I. $(DEFINES) +CFLAGS = -Wall -O3 -std=gnu99 -I. -all: $(TARGET) +all: $(TARGET) config.mk + +config.mk: configure qb/* + @echo "config.mk is outdated or non-existing. Run ./configure again." + exit 1 ssnes: $(OBJ) $(CXX) -o $@ $(OBJ) $(LIBS) $(CFLAGS) diff --git a/qb/config.libs.sh b/qb/config.libs.sh index 16de364dbc..5277aee880 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -5,6 +5,7 @@ check_critical C99 "Cannot find C99 compatible compiler." check_lib_cxx SNES $LIBSNES snes_init -ldl check_critical SNES "Cannot find libsnes." +add_define_make libsnes $LIBSNES check_lib ALSA -lasound snd_pcm_open check_header OSS sys/soundcard.h From 9006c77fcf732573397d38a8b1d155c346591675 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 02:57:05 +0100 Subject: [PATCH 23/47] remove unneeded config.mk.def --- config.mk.def | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 config.mk.def diff --git a/config.mk.def b/config.mk.def deleted file mode 100644 index 9d677deeae..0000000000 --- a/config.mk.def +++ /dev/null @@ -1,13 +0,0 @@ - -BUILD_OPENGL = 1 -BUILD_CG = 0 -BUILD_FILTER = 0 - -BUILD_RSOUND = 0 -BUILD_OSS = 0 -BUILD_ALSA = 1 -BUILD_ROAR = 0 -BUILD_AL = 0 - - -PREFIX = /usr/local From 38616ee7940f56c38cdcfd06880c7e7ce90424db Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 03:02:30 +0100 Subject: [PATCH 24/47] More cleanup... --- Makefile | 2 +- driver.c | 3 ++- hqflt/filters.h | 2 ++ qb/config.libs.sh | 4 +++- qb/config.params.sh | 2 +- qb/qb.libs.sh | 4 ++-- settings.c | 1 + 7 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 7777d418d6..02c4e9a6b5 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ ifeq ($(HAVE_AL), 1) LIBS += -lopenal endif -ifeq ($(HAVE_OPENGL), 1) +ifeq ($(HAVE_GLFW), 1) OBJ += gfx/gl.o LIBS += -lglfw endif diff --git a/driver.c b/driver.c index 425519fd92..c1d451906f 100644 --- a/driver.c +++ b/driver.c @@ -21,6 +21,7 @@ #include #include #include "hqflt/filters.h" +#include "config.h" static const audio_driver_t *audio_drivers[] = { #ifdef HAVE_ALSA @@ -41,7 +42,7 @@ static const audio_driver_t *audio_drivers[] = { }; static const video_driver_t *video_drivers[] = { -#ifdef HAVE_GL +#ifdef HAVE_GLFW &video_gl, #endif }; diff --git a/hqflt/filters.h b/hqflt/filters.h index e375b09f41..439b3f3727 100644 --- a/hqflt/filters.h +++ b/hqflt/filters.h @@ -19,6 +19,8 @@ #ifndef __FILTERS_H #define __FILTERS_H +#include "config.h" + #ifdef HAVE_FILTER #include "pastlib.h" diff --git a/qb/config.libs.sh b/qb/config.libs.sh index 5277aee880..5dd6cf36f2 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -16,10 +16,12 @@ check_lib ROAR -lroar roar_vs_new check_lib GLFW -lglfw glfwInit check_critical GLFW "Cannot find GLFW library." +check_lib CG -lCg cgCreateContext + check_lib SRC -lsamplerate src_callback_new # Creates config.mk. -VARS="ALSA OSS AL RSOUND ROAR GLFW FILTERS" +VARS="ALSA OSS AL RSOUND ROAR GLFW FILTER CG" create_config_make config.mk $VARS create_config_header config.h $VARS diff --git a/qb/config.params.sh b/qb/config.params.sh index e3c8e271ac..768550b26b 100644 --- a/qb/config.params.sh +++ b/qb/config.params.sh @@ -8,7 +8,7 @@ PACKAGE_VERSION=0.1 # $2: Comment # $3: Default arg. auto implies that HAVE_ALSA will be set according to library checks later on. add_command_line_string LIBSNES "libsnes library used" "-lsnes" -add_command_line_enable FILTERS "Disable CPU filter support" yes +add_command_line_enable FILTER "Disable CPU filter support" yes add_command_line_enable CG "Enable CG shader support" auto add_command_line_enable ALSA "Enable ALSA support" auto add_command_line_enable OSS "Enable OSS support" auto diff --git a/qb/qb.libs.sh b/qb/qb.libs.sh index 30a13f2219..ab8585fc83 100644 --- a/qb/qb.libs.sh +++ b/qb/qb.libs.sh @@ -277,9 +277,9 @@ create_config_make() do tmpval="HAVE_$1" eval tmpval=\$$tmpval - if [ $tmpval = yes ]; then + if [ "$tmpval" = yes ]; then echo "HAVE_$1 = 1" >> "$outfile" - elif [ $tmpval = no ]; then + elif [ "$tmpval" = no ]; then echo "HAVE_$1 = 0" >> "$outfile" fi diff --git a/settings.c b/settings.c index b131d24381..26c85ca736 100644 --- a/settings.c +++ b/settings.c @@ -21,6 +21,7 @@ #include #include #include "hqflt/filters.h" +#include "config.h" struct settings g_settings; From 5824f081f7092d6d2f7127187328d7f30c75a360 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 03:23:12 +0100 Subject: [PATCH 25/47] Slight update in makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 02c4e9a6b5..83f7d6b9cd 100644 --- a/Makefile +++ b/Makefile @@ -49,7 +49,7 @@ all: $(TARGET) config.mk config.mk: configure qb/* @echo "config.mk is outdated or non-existing. Run ./configure again." - exit 1 + @exit 1 ssnes: $(OBJ) $(CXX) -o $@ $(OBJ) $(LIBS) $(CFLAGS) From 88084c8530a92b0096f89e3766fa8bc2eea1edc5 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 03:37:51 +0100 Subject: [PATCH 26/47] Fix cg path option and fullscreen. --- settings.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/settings.c b/settings.c index 26c85ca736..c0fde23a11 100644 --- a/settings.c +++ b/settings.c @@ -154,6 +154,9 @@ void parse_config(void) if (config_get_int(conf, "video_fullscreen_y", &tmp_int)) g_settings.video.fullscreen_y = tmp_int; + if (config_get_bool(conf, "video_fullscreen", &tmp_bool)) + g_settings.video.fullscreen = tmp_bool; + if (config_get_bool(conf, "video_vsync", &tmp_bool)) g_settings.video.vsync = tmp_bool; @@ -248,11 +251,6 @@ void parse_config(void) free(tmp_str); } - if (config_get_string(conf, "video_cg_shader_path", &tmp_str)) - { - strncpy(g_settings.video.cg_shader_path, tmp_str, sizeof(g_settings.video.cg_shader_path) - 1); - free(tmp_str); - } // TODO: Keybinds. From db3ec95ee5cf87aec5b2dfc4306de2f9b8fe1919 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 03:41:40 +0100 Subject: [PATCH 27/47] Add ssnes.cfg --- ssnes.cfg | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 ssnes.cfg diff --git a/ssnes.cfg b/ssnes.cfg new file mode 100644 index 0000000000..e8bcc5e2f7 --- /dev/null +++ b/ssnes.cfg @@ -0,0 +1,29 @@ +##### Config file for SSNES + +#### Video + +# video_xscale = +# video_yscale = +# video_fullscreen_x = +# video_fullscreen_y = +# video_fullscreen = +# video_vsync = +# video_smooth = +# video_force_aspect = +# video_cg_shader = +# video_filter = + +#### Audio + +# audio_enable = +# audio_out_rate = +# audio_in_rate = +# audio_driver = +# audio_device = +# audio_sync = +# audio_latency = +# audio_src_quality = + +### Input + +# input_axis_threshold = From b1a7a11dfcd93b95a5ae4f446dd0de03f03f73bd Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 03:42:31 +0100 Subject: [PATCH 28/47] Change path for /etc config. --- Makefile | 1 + settings.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 83f7d6b9cd..2fe33ca37d 100644 --- a/Makefile +++ b/Makefile @@ -59,6 +59,7 @@ ssnes: $(OBJ) install: $(TARGET) install -m755 $(TARGET) $(PREFIX)/bin + install -m644 ssnes.cfg /etc/ssnes.cfg uninstall: $(TARGET) rm -rf $(PREFIX)/bin/$(TARGET) diff --git a/settings.c b/settings.c index c0fde23a11..57988210ad 100644 --- a/settings.c +++ b/settings.c @@ -128,8 +128,8 @@ void parse_config(void) strcat(conf_path, "/.ssnesrc"); conf = config_file_new(conf_path); } - else // Try /etc/ssnes.conf as a final test ... - conf = config_file_new("/etc/ssnes.conf"); + else // Try /etc/ssnes.cfg as a final test ... + conf = config_file_new("/etc/ssnes.cfg"); } set_defaults(); From d9aa1dd48fa0e28874511d6002fca0e905c91fbf Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 04:51:08 +0100 Subject: [PATCH 29/47] Getting some work on keybinds! --- settings.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++ ssnes.cfg | 65 ++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+) diff --git a/settings.c b/settings.c index 57988210ad..ddd4832e4a 100644 --- a/settings.c +++ b/settings.c @@ -22,9 +22,12 @@ #include #include "hqflt/filters.h" #include "config.h" +#include struct settings g_settings; +static void read_keybinds(config_file_t *conf); + static void set_defaults(void) { const char *def_video = NULL; @@ -251,8 +254,113 @@ void parse_config(void) free(tmp_str); } + read_keybinds(conf); // TODO: Keybinds. config_file_free(conf); } + +struct bind_map +{ + const char *key; + int snes_key; +}; + +static const struct bind_map bind_maps[2][12] = { + { + { "input_player1_a", SNES_DEVICE_ID_JOYPAD_A }, + { "input_player1_b", SNES_DEVICE_ID_JOYPAD_B }, + { "input_player1_y", SNES_DEVICE_ID_JOYPAD_Y }, + { "input_player1_x", SNES_DEVICE_ID_JOYPAD_X }, + { "input_player1_start", SNES_DEVICE_ID_JOYPAD_START }, + { "input_player1_select", SNES_DEVICE_ID_JOYPAD_SELECT }, + { "input_player1_l", SNES_DEVICE_ID_JOYPAD_L }, + { "input_player1_r", SNES_DEVICE_ID_JOYPAD_R }, + { "input_player1_left", SNES_DEVICE_ID_JOYPAD_LEFT }, + { "input_player1_right", SNES_DEVICE_ID_JOYPAD_RIGHT }, + { "input_player1_up", SNES_DEVICE_ID_JOYPAD_UP }, + { "input_player1_down", SNES_DEVICE_ID_JOYPAD_DOWN }, + }, + { + { "input_player2_a", SNES_DEVICE_ID_JOYPAD_A }, + { "input_player2_b", SNES_DEVICE_ID_JOYPAD_B }, + { "input_player2_y", SNES_DEVICE_ID_JOYPAD_Y }, + { "input_player2_x", SNES_DEVICE_ID_JOYPAD_X }, + { "input_player2_start", SNES_DEVICE_ID_JOYPAD_START }, + { "input_player2_select", SNES_DEVICE_ID_JOYPAD_SELECT }, + { "input_player2_l", SNES_DEVICE_ID_JOYPAD_L }, + { "input_player2_r", SNES_DEVICE_ID_JOYPAD_R }, + { "input_player2_left", SNES_DEVICE_ID_JOYPAD_LEFT }, + { "input_player2_right", SNES_DEVICE_ID_JOYPAD_RIGHT }, + { "input_player2_up", SNES_DEVICE_ID_JOYPAD_UP }, + { "input_player2_down", SNES_DEVICE_ID_JOYPAD_DOWN }, + } +}; + +struct glfw_map +{ + const char *str; + int key; +}; + +// Edit: Not portable to different input systems atm. Might move this map into the driver itself or something. +static const struct glfw_map glfw_map[] = { + { "left", GLFW_KEY_LEFT }, + { "right", GLFW_KEY_RIGHT }, + { "up", GLFW_KEY_UP }, + { "down", GLFW_KEY_DOWN }, + { "enter", GLFW_KEY_ENTER }, + { "rshift", GLFW_KEY_RSHIFT }, + { "space", GLFW_KEY_SPACE } +}; + +static struct snes_keybind *find_snes_bind(unsigned port, int id) +{ + struct snes_keybind *binds = g_settings.input.binds[port]; + + for (int i = 0; binds[i].id != -1; i++) + { + if (id == binds[i].id) + return &binds[i]; + } + return NULL; +} + +static int find_glfw_bind(const char *str) +{ + for (int i = 0; i < sizeof(glfw_map)/sizeof(struct glfw_map); i++) + { + if (strcasecmp(glfw_map[i].str, str) == 0) + return glfw_map[i].key; + } + return -1; +} + +void read_keybinds(config_file_t *conf) +{ + char *tmp_str; + int glfw_key; + + for (int j = 0; j < 1; j++) + { + for (int i = 0; i < sizeof(bind_maps[j])/sizeof(struct bind_map); i++) + { + if (config_get_string(conf, bind_maps[j][i].key, &tmp_str)) + { + // If the bind is a normal key-press ... + if (strlen(tmp_str) == 1 && isalpha(*tmp_str)) + glfw_key = toupper(*tmp_str); + else // Check if we have a special mapping for it. + glfw_key = find_glfw_bind(tmp_str); + + struct snes_keybind *bind = find_snes_bind(0, bind_maps[j][i].snes_key); + + if (bind && glfw_key >= 0) + bind->key = glfw_key; + + free(tmp_str); + } + } + } +} diff --git a/ssnes.cfg b/ssnes.cfg index e8bcc5e2f7..46fa9ecd82 100644 --- a/ssnes.cfg +++ b/ssnes.cfg @@ -27,3 +27,68 @@ ### Input # input_axis_threshold = + +input_player1_a = t +input_player1_b = y +input_player1_y = +input_player1_x = +input_player1_start = +input_player1_select = +input_player1_l = +input_player1_r = +input_player1_left = +input_player1_right = +input_player1_up = +input_player1_down = + +input_player1_a_btn = +input_player1_b_btn = +input_player1_y_btn = +input_player1_x_btn = +input_player1_start_btn = +input_player1_select_btn = +input_player1_l_btn = +input_player1_r_btn = +input_player1_left_btn = +input_player1_right_btn = +input_player1_up_btn = +input_player1_down_btn = +input_player1_left_axis = +input_player1_right_axis = +input_player1_up_axis = +input_player1_down_axis = + +input_player2_a = +input_player2_b = +input_player2_y = +input_player2_x = +input_player2_start = +input_player2_select = +input_player2_l = +input_player2_r = +input_player2_left = +input_player2_right = +input_player2_up = +input_player2_down = + +input_player2_a_btn = +input_player2_b_btn = +input_player2_y_btn = +input_player2_x_btn = +input_player2_start_btn = +input_player2_select_btn = +input_player2_l_btn = +input_player2_r_btn = +input_player2_left_btn = +input_player2_right_btn = +input_player2_up_btn = +input_player2_down_btn = +input_player2_left_axis = +input_player2_right_axis = +input_player2_up_axis = +input_player2_down_axis = + +input_toggle_fast_forward = +input_toggle_fullscreen = +input_save_state = +input_load_state = From 03a0d8a4075a3ceba86f83192b17998686e9e38e Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 05:30:47 +0100 Subject: [PATCH 30/47] Bindings should be somewhat complete now... --- settings.c | 138 ++++++++++++++++++++++++++++++++++++++--------------- ssnes.cfg | 6 ++- 2 files changed, 104 insertions(+), 40 deletions(-) diff --git a/settings.c b/settings.c index ddd4832e4a..f294d5a528 100644 --- a/settings.c +++ b/settings.c @@ -264,37 +264,41 @@ void parse_config(void) struct bind_map { const char *key; + const char *btn; + const char *axis; int snes_key; }; -static const struct bind_map bind_maps[2][12] = { +static const struct bind_map bind_maps[2][13] = { { - { "input_player1_a", SNES_DEVICE_ID_JOYPAD_A }, - { "input_player1_b", SNES_DEVICE_ID_JOYPAD_B }, - { "input_player1_y", SNES_DEVICE_ID_JOYPAD_Y }, - { "input_player1_x", SNES_DEVICE_ID_JOYPAD_X }, - { "input_player1_start", SNES_DEVICE_ID_JOYPAD_START }, - { "input_player1_select", SNES_DEVICE_ID_JOYPAD_SELECT }, - { "input_player1_l", SNES_DEVICE_ID_JOYPAD_L }, - { "input_player1_r", SNES_DEVICE_ID_JOYPAD_R }, - { "input_player1_left", SNES_DEVICE_ID_JOYPAD_LEFT }, - { "input_player1_right", SNES_DEVICE_ID_JOYPAD_RIGHT }, - { "input_player1_up", SNES_DEVICE_ID_JOYPAD_UP }, - { "input_player1_down", SNES_DEVICE_ID_JOYPAD_DOWN }, + { "input_player1_a", "input_player1_a_btn", NULL, SNES_DEVICE_ID_JOYPAD_A }, + { "input_player1_b", "input_player1_b_btn", NULL, SNES_DEVICE_ID_JOYPAD_B }, + { "input_player1_y", "input_player1_y_btn", NULL, SNES_DEVICE_ID_JOYPAD_Y }, + { "input_player1_x", "input_player1_x_btn", NULL, SNES_DEVICE_ID_JOYPAD_X }, + { "input_player1_start", "input_player1_start_btn", NULL, SNES_DEVICE_ID_JOYPAD_START }, + { "input_player1_select", "input_player1_select_btn", NULL, SNES_DEVICE_ID_JOYPAD_SELECT }, + { "input_player1_l", "input_player1_l_btn", NULL, SNES_DEVICE_ID_JOYPAD_L }, + { "input_player1_r", "input_player1_r_btn", NULL, SNES_DEVICE_ID_JOYPAD_R }, + { "input_player1_left", "input_player1_left_btn", "input_player1_left_axis", SNES_DEVICE_ID_JOYPAD_LEFT }, + { "input_player1_right", "input_player1_right_btn", "input_player1_right_axis", SNES_DEVICE_ID_JOYPAD_RIGHT }, + { "input_player1_up", "input_player1_up_btn", "input_player1_up_axis", SNES_DEVICE_ID_JOYPAD_UP }, + { "input_player1_down", "input_player1_down_btn", "input_player1_down_axis", SNES_DEVICE_ID_JOYPAD_DOWN }, + { "input_toggle_fast_forward", "input_toggle_fast_forward_btn", NULL, SNES_FAST_FORWARD_KEY } }, { - { "input_player2_a", SNES_DEVICE_ID_JOYPAD_A }, - { "input_player2_b", SNES_DEVICE_ID_JOYPAD_B }, - { "input_player2_y", SNES_DEVICE_ID_JOYPAD_Y }, - { "input_player2_x", SNES_DEVICE_ID_JOYPAD_X }, - { "input_player2_start", SNES_DEVICE_ID_JOYPAD_START }, - { "input_player2_select", SNES_DEVICE_ID_JOYPAD_SELECT }, - { "input_player2_l", SNES_DEVICE_ID_JOYPAD_L }, - { "input_player2_r", SNES_DEVICE_ID_JOYPAD_R }, - { "input_player2_left", SNES_DEVICE_ID_JOYPAD_LEFT }, - { "input_player2_right", SNES_DEVICE_ID_JOYPAD_RIGHT }, - { "input_player2_up", SNES_DEVICE_ID_JOYPAD_UP }, - { "input_player2_down", SNES_DEVICE_ID_JOYPAD_DOWN }, + { "input_player2_a", "input_player2_a_btn", NULL, SNES_DEVICE_ID_JOYPAD_A }, + { "input_player2_b", "input_player2_b_btn", NULL, SNES_DEVICE_ID_JOYPAD_B }, + { "input_player2_y", "input_player2_y_btn", NULL, SNES_DEVICE_ID_JOYPAD_Y }, + { "input_player2_x", "input_player2_x_btn", NULL, SNES_DEVICE_ID_JOYPAD_X }, + { "input_player2_start", "input_player2_start_btn", NULL, SNES_DEVICE_ID_JOYPAD_START }, + { "input_player2_select", "input_player2_select_btn", NULL, SNES_DEVICE_ID_JOYPAD_SELECT }, + { "input_player2_l", "input_player2_l_btn", NULL, SNES_DEVICE_ID_JOYPAD_L }, + { "input_player2_r", "input_player2_r_btn", NULL, SNES_DEVICE_ID_JOYPAD_R }, + { "input_player2_left", "input_player2_left_btn", "input_player2_left_axis", SNES_DEVICE_ID_JOYPAD_LEFT }, + { "input_player2_right", "input_player2_right_btn", "input_player2_right_axis", SNES_DEVICE_ID_JOYPAD_RIGHT }, + { "input_player2_up", "input_player2_up_btn", "input_player2_up_axis", SNES_DEVICE_ID_JOYPAD_UP }, + { "input_player2_down", "input_player2_down_btn", "input_player2_down_axis", SNES_DEVICE_ID_JOYPAD_DOWN }, + { "input_toggle_fast_forward", "input_toggle_fast_forward_btn", NULL, SNES_FAST_FORWARD_KEY } } }; @@ -337,30 +341,88 @@ static int find_glfw_bind(const char *str) return -1; } -void read_keybinds(config_file_t *conf) +static int find_glfw_key(const char *str) { - char *tmp_str; - int glfw_key; + // If the bind is a normal key-press ... + if (strlen(str) == 1 && isalpha(*str)) + return toupper(*str); + else // Check if we have a special mapping for it. + return find_glfw_bind(str); +} + +static void read_keybinds(config_file_t *conf) +{ + char *tmp_key = NULL; + int tmp_btn; + char *tmp_axis = NULL; for (int j = 0; j < 1; j++) { for (int i = 0; i < sizeof(bind_maps[j])/sizeof(struct bind_map); i++) { - if (config_get_string(conf, bind_maps[j][i].key, &tmp_str)) + struct snes_keybind *bind = find_snes_bind(j, bind_maps[j][i].snes_key); + if (!bind) + continue; + + if (bind_maps[j][i].key && config_get_string(conf, bind_maps[j][i].key, &tmp_key)) { - // If the bind is a normal key-press ... - if (strlen(tmp_str) == 1 && isalpha(*tmp_str)) - glfw_key = toupper(*tmp_str); - else // Check if we have a special mapping for it. - glfw_key = find_glfw_bind(tmp_str); + int key = find_glfw_key(tmp_key); - struct snes_keybind *bind = find_snes_bind(0, bind_maps[j][i].snes_key); + if (key >= 0) + bind->key = key; - if (bind && glfw_key >= 0) - bind->key = glfw_key; + free(tmp_key); + tmp_key = NULL; + } - free(tmp_str); + if (bind_maps[j][i].btn && config_get_int(conf, bind_maps[j][i].btn, &tmp_btn)) + { + if (tmp_btn >= 0) + bind->joykey = tmp_btn; + } + + if (bind_maps[j][i].axis && config_get_string(conf, bind_maps[j][i].axis, &tmp_axis)) + { + if (strlen(tmp_axis) >= 2 && (*tmp_axis == '+' || *tmp_axis == '-')) + { + int axis = strtol(tmp_axis + 1, NULL, 0); + if (*tmp_axis == '+') + bind->joyaxis = AXIS_POS(axis); + else + bind->joyaxis = AXIS_NEG(axis); + + } + free(tmp_axis); + tmp_axis = NULL; } } } + + char *tmp_str; + if (config_get_string(conf, "input_toggle_fullscreen", &tmp_str)) + { + int key = find_glfw_key(tmp_str); + if (key >= 0) + g_settings.input.toggle_fullscreen_key = key; + free(tmp_str); + } + if (config_get_string(conf, "input_save_state", &tmp_str)) + { + int key = find_glfw_key(tmp_str); + if (key >= 0) + g_settings.input.save_state_key = key; + free(tmp_str); + } + if (config_get_string(conf, "input_load_state", &tmp_str)) + { + int key = find_glfw_key(tmp_str); + if (key >= 0) + g_settings.input.load_state_key = key; + free(tmp_str); + } + } + + + + diff --git a/ssnes.cfg b/ssnes.cfg index 46fa9ecd82..a4e3c42878 100644 --- a/ssnes.cfg +++ b/ssnes.cfg @@ -88,7 +88,9 @@ input_player2_right_axis = input_player2_up_axis = input_player2_down_axis = -input_toggle_fast_forward = -input_toggle_fullscreen = +input_toggle_fullscreen = l input_save_state = input_load_state = + +input_toggle_fast_forward = o +input_toggle_fast_forward_btn = From b96d585acb170b603b8b1c151c88dc1ed971c3ac Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 05:40:57 +0100 Subject: [PATCH 31/47] update settings file --- settings.c | 1 - ssnes.cfg | 124 +++++++++++++++++++++++++++-------------------------- 2 files changed, 63 insertions(+), 62 deletions(-) diff --git a/settings.c b/settings.c index f294d5a528..05f68bf1d7 100644 --- a/settings.c +++ b/settings.c @@ -420,7 +420,6 @@ static void read_keybinds(config_file_t *conf) g_settings.input.load_state_key = key; free(tmp_str); } - } diff --git a/ssnes.cfg b/ssnes.cfg index a4e3c42878..3edf4a0ff0 100644 --- a/ssnes.cfg +++ b/ssnes.cfg @@ -28,69 +28,71 @@ # input_axis_threshold = -input_player1_a = t -input_player1_b = y -input_player1_y = -input_player1_x = -input_player1_start = -input_player1_select = -input_player1_l = -input_player1_r = -input_player1_left = -input_player1_right = -input_player1_up = -input_player1_down = +# input_player1_a = t +# input_player1_b = y +# input_player1_y = +# input_player1_x = +# input_player1_start = +# input_player1_select = +# input_player1_l = +# input_player1_r = +# input_player1_left = +# input_player1_right = +# input_player1_up = +# input_player1_down = -input_player1_a_btn = -input_player1_b_btn = -input_player1_y_btn = -input_player1_x_btn = -input_player1_start_btn = -input_player1_select_btn = -input_player1_l_btn = -input_player1_r_btn = -input_player1_left_btn = -input_player1_right_btn = -input_player1_up_btn = -input_player1_down_btn = -input_player1_left_axis = -input_player1_right_axis = -input_player1_up_axis = -input_player1_down_axis = +# input_player1_a_btn = +# input_player1_b_btn = +# input_player1_y_btn = +# input_player1_x_btn = +# input_player1_start_btn = +# input_player1_select_btn = +# input_player1_l_btn = +# input_player1_r_btn = +# input_player1_left_btn = +# input_player1_right_btn = +# input_player1_up_btn = +# input_player1_down_btn = -input_player2_a = -input_player2_b = -input_player2_y = -input_player2_x = -input_player2_start = -input_player2_select = -input_player2_l = -input_player2_r = -input_player2_left = -input_player2_right = -input_player2_up = -input_player2_down = +# input_player1_left_axis = +# input_player1_right_axis = +# input_player1_up_axis = +# input_player1_down_axis = -input_player2_a_btn = -input_player2_b_btn = -input_player2_y_btn = -input_player2_x_btn = -input_player2_start_btn = -input_player2_select_btn = -input_player2_l_btn = -input_player2_r_btn = -input_player2_left_btn = -input_player2_right_btn = -input_player2_up_btn = -input_player2_down_btn = -input_player2_left_axis = -input_player2_right_axis = -input_player2_up_axis = -input_player2_down_axis = +# input_player2_a = +# input_player2_b = +# input_player2_y = +# input_player2_x = +# input_player2_start = +# input_player2_select = +# input_player2_l = +# input_player2_r = +# input_player2_left = +# input_player2_right = +# input_player2_up = +# input_player2_down = -input_toggle_fullscreen = l -input_save_state = -input_load_state = +# input_player2_a_btn = +# input_player2_b_btn = +# input_player2_y_btn = +# input_player2_x_btn = +# input_player2_start_btn = +# input_player2_select_btn = +# input_player2_l_btn = +# input_player2_r_btn = +# input_player2_left_btn = +# input_player2_right_btn = +# input_player2_up_btn = +# input_player2_down_btn = -input_toggle_fast_forward = o -input_toggle_fast_forward_btn = +# input_player2_left_axis = +# input_player2_right_axis = +# input_player2_up_axis = +# input_player2_down_axis = + +# input_toggle_fullscreen = +# input_save_state = +# input_load_state = + +# input_toggle_fast_forward = +# input_toggle_fast_forward_btn = From 0dde1ce7d1e118d2b119f1ea4528521302127562 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 05:51:11 +0100 Subject: [PATCH 32/47] Add destdir --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 2fe33ca37d..33598ae5dd 100644 --- a/Makefile +++ b/Makefile @@ -58,11 +58,11 @@ ssnes: $(OBJ) $(CC) $(CFLAGS) -c -o $@ $< install: $(TARGET) - install -m755 $(TARGET) $(PREFIX)/bin - install -m644 ssnes.cfg /etc/ssnes.cfg + install -m755 $(TARGET) $(DESTDIR)/$(PREFIX)/bin + install -m644 ssnes.cfg $(DESTDIR)/etc/ssnes.cfg uninstall: $(TARGET) - rm -rf $(PREFIX)/bin/$(TARGET) + rm -rf $(DESTDIR)/$(PREFIX)/bin/$(TARGET) clean: rm -f *.o From 981aa2bdd76e95173f79db6544992695d72bf117 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 05:55:07 +0100 Subject: [PATCH 33/47] Test /etc/ssnes.conf properly --- settings.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/settings.c b/settings.c index 05f68bf1d7..af2a886ff1 100644 --- a/settings.c +++ b/settings.c @@ -131,7 +131,8 @@ void parse_config(void) strcat(conf_path, "/.ssnesrc"); conf = config_file_new(conf_path); } - else // Try /etc/ssnes.cfg as a final test ... + // Try this as a last chance... + if (!conf) conf = config_file_new("/etc/ssnes.cfg"); } From b34554c8e569dd1117c1a2215ab068b95d6c8b4d Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 12:34:23 +0100 Subject: [PATCH 34/47] Added more maps to glfw --- general.h | 1 + settings.c | 26 +++++++- ssnes.cfg | 179 +++++++++++++++++++++++++++++++++-------------------- 3 files changed, 139 insertions(+), 67 deletions(-) diff --git a/general.h b/general.h index 3b86a831cd..1a5a2acfd7 100644 --- a/general.h +++ b/general.h @@ -63,6 +63,7 @@ struct settings int save_state_key; int load_state_key; int toggle_fullscreen_key; + int exit_emulator_key; float axis_threshold; } input; }; diff --git a/settings.c b/settings.c index af2a886ff1..307cf6b73b 100644 --- a/settings.c +++ b/settings.c @@ -97,6 +97,7 @@ static void set_defaults(void) g_settings.input.load_state_key = LOAD_STATE_KEY; g_settings.input.toggle_fullscreen_key = TOGGLE_FULLSCREEN; g_settings.input.axis_threshold = AXIS_THRESHOLD; + g_settings.input.exit_emulator_key = GLFW_KEY_ESC; } void parse_config(void) @@ -317,7 +318,23 @@ static const struct glfw_map glfw_map[] = { { "down", GLFW_KEY_DOWN }, { "enter", GLFW_KEY_ENTER }, { "rshift", GLFW_KEY_RSHIFT }, - { "space", GLFW_KEY_SPACE } + { "shift", GLFW_KEY_LSHIFT }, + { "ctrl", GLFW_KEY_LCTRL }, + { "alt", GLFW_KEY_LALT }, + { "space", GLFW_KEY_SPACE }, + { "escape", GLFW_KEY_ESC }, + { "f1", GLFW_KEY_F1 }, + { "f2", GLFW_KEY_F2 }, + { "f3", GLFW_KEY_F3 }, + { "f4", GLFW_KEY_F4 }, + { "f5", GLFW_KEY_F5 }, + { "f6", GLFW_KEY_F6 }, + { "f7", GLFW_KEY_F7 }, + { "f8", GLFW_KEY_F8 }, + { "f9", GLFW_KEY_F9 }, + { "f10", GLFW_KEY_F10 }, + { "f11", GLFW_KEY_F11 }, + { "f12", GLFW_KEY_F12 }, }; static struct snes_keybind *find_snes_bind(unsigned port, int id) @@ -421,6 +438,13 @@ static void read_keybinds(config_file_t *conf) g_settings.input.load_state_key = key; free(tmp_str); } + if (config_get_string(conf, "input_exit_emulator", &tmp_str)) + { + int key = find_glfw_key(tmp_str); + if (key >= 0) + g_settings.input.exit_emulator_key = key; + free(tmp_str); + } } diff --git a/ssnes.cfg b/ssnes.cfg index 3edf4a0ff0..f2c70d5a7d 100644 --- a/ssnes.cfg +++ b/ssnes.cfg @@ -2,63 +2,101 @@ #### Video -# video_xscale = -# video_yscale = -# video_fullscreen_x = -# video_fullscreen_y = -# video_fullscreen = -# video_vsync = -# video_smooth = -# video_force_aspect = -# video_cg_shader = -# video_filter = +# Windowed xscale and yscale (Real x res: 296 * xscale, real y scale: 224 * xscale) +# video_xscale = 3.0 +# video_yscale = 3.0 + +# Fullscreen resolution +# video_fullscreen_x = 1280 +# video_fullscreen_y = 720 + +# Start in fullscreen. Can be changed at runtime. +# video_fullscreen = false + +# Video vsync. +# video_vsync = true + +# Smoothens picture with bilinear filtering. Should be disabled if using Cg shaders. +# video_smooth = true + +# Forces rendering area to stay 4:3. +# video_force_aspect = true + +# Path to Cg shader. If enabled +# video_cg_shader = "/path/to/cg/shader.cg" + +# CPU-based filter. Valid ones are: hq2x, hq4x, grayscale, bleed, ntsc. +# video_filter = ntsc #### Audio -# audio_enable = -# audio_out_rate = -# audio_in_rate = -# audio_driver = +# Enable audio. +# audio_enable = true + +# Audio output samplerate. +# audio_out_rate = 48000 + +# Audio input samplerate from libsnes. +# Lower this (slightly) if you are experiencing frequent audio dropouts while vsync is enabled. +# Conversely, increase this slightly if you are experiencing good audio, +# but lots of dropped frames. Reasonable values for this is 32000 +/- 100 Hz. +# audio_in_rate = 31950 + +# Audio driver backend. Depending on configuration possible candidates are: alsa, oss, rsound, roar, openal +# audio_driver = alsa + +# Override the default audio device the audio_driver uses. # audio_device = -# audio_sync = -# audio_latency = + +# Will sync (block) on audio. Recommended. +# audio_sync = true + +# Desired audio latency in milliseconds. Might not be honored if driver can't provide given latency. +# audio_latency = 64 + +# libsamplerate quality. Valid values are from 1 to 5. These values map to zero_order_hold, linear, sinc_fastest, sinc_medium and sinc_best. # audio_src_quality = ### Input -# input_axis_threshold = +# Defines axis threshold. Possible values are [0.0, 1.0] +# input_axis_threshold = 0.6 -# input_player1_a = t -# input_player1_b = y -# input_player1_y = -# input_player1_x = -# input_player1_start = -# input_player1_select = -# input_player1_l = -# input_player1_r = -# input_player1_left = -# input_player1_right = -# input_player1_up = -# input_player1_down = +# Keyboard input. Will recognize normal keypresses and special keys like "left", "right", and so on. +# input_player1_a = x +# input_player1_b = z +# input_player1_y = a +# input_player1_x = s +# input_player1_start = enter +# input_player1_select = rshift +# input_player1_l = q +# input_player1_r = w +# input_player1_left = left +# input_player1_right = right +# input_player1_up = up +# input_player1_down = down -# input_player1_a_btn = -# input_player1_b_btn = -# input_player1_y_btn = -# input_player1_x_btn = -# input_player1_start_btn = -# input_player1_select_btn = -# input_player1_l_btn = -# input_player1_r_btn = -# input_player1_left_btn = -# input_player1_right_btn = -# input_player1_up_btn = -# input_player1_down_btn = +# Joypad buttons. Figure these out by looking at jstest /dev/input/js0 output. +# input_player1_a_btn = 1 +# input_player1_b_btn = 0 +# input_player1_y_btn = 2 +# input_player1_x_btn = 3 +# input_player1_start_btn = 7 +# input_player1_select_btn = 6 +# input_player1_l_btn = 4 +# input_player1_r_btn = 5 +# input_player1_left_btn = 11 +# input_player1_right_btn = 12 +# input_player1_up_btn = 13 +# input_player1_down_btn = 14 -# input_player1_left_axis = -# input_player1_right_axis = -# input_player1_up_axis = -# input_player1_down_axis = +# Axis for DPAD. Needs to be either '+' or '-' in the first character signaling either positive or negative direction of the axis, then the axis number. +# input_player1_left_axis = -0 +# input_player1_right_axis = +0 +# input_player1_up_axis = +1 +# input_player1_down_axis = -1 +# Same stuff, just for player two. # input_player2_a = # input_player2_b = # input_player2_y = @@ -72,27 +110,36 @@ # input_player2_up = # input_player2_down = -# input_player2_a_btn = -# input_player2_b_btn = -# input_player2_y_btn = -# input_player2_x_btn = -# input_player2_start_btn = -# input_player2_select_btn = -# input_player2_l_btn = -# input_player2_r_btn = -# input_player2_left_btn = -# input_player2_right_btn = -# input_player2_up_btn = -# input_player2_down_btn = +# input_player2_a_btn = 1 +# input_player2_b_btn = 0 +# input_player2_y_btn = 2 +# input_player2_x_btn = 3 +# input_player2_start_btn = 7 +# input_player2_select_btn = 6 +# input_player2_l_btn = 4 +# input_player2_r_btn = 5 +# input_player2_left_btn = 11 +# input_player2_right_btn = 12 +# input_player2_up_btn = 13 +# input_player2_down_btn = 14 -# input_player2_left_axis = -# input_player2_right_axis = -# input_player2_up_axis = -# input_player2_down_axis = -# input_toggle_fullscreen = -# input_save_state = -# input_load_state = +# input_player2_left_axis = -0 +# input_player2_right_axis = +0 +# input_player2_up_axis = +1 +# input_player2_down_axis = -1 -# input_toggle_fast_forward = -# input_toggle_fast_forward_btn = +# Toggles fullscreen. +# input_toggle_fullscreen = f +# Saves state. +# input_save_state = f2 +# Loads state. +# input_load_state = f4 + +# Toggles between fast-forwarding and normal speed. +# input_toggle_fast_forward = space +# Same, just mapping to a joypad button. +# input_toggle_fast_forward_btn = 10 + +# Key to exit emulator cleanly. +# input_exit_emulator = escape From 5b58630bbb78ccaf77ce559e7e161c72a12013b1 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 12:35:13 +0100 Subject: [PATCH 35/47] Use settings key --- ssnes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssnes.c b/ssnes.c index 247f55e3e2..7ed7223f08 100644 --- a/ssnes.c +++ b/ssnes.c @@ -336,7 +336,7 @@ int main(int argc, char *argv[]) ///// TODO: Modular friendly!!! for(;;) { - bool quitting = glfwGetKey(GLFW_KEY_ESC) || !glfwGetWindowParam(GLFW_OPENED); + bool quitting = glfwGetKey(g_settings.input.exit_emulator_key) || !glfwGetWindowParam(GLFW_OPENED); if ( quitting ) break; From 9da15e975e988c3b86861e1464e099069c1e56ad Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 12:54:16 +0100 Subject: [PATCH 36/47] Add config.h to gl.c --- gfx/gl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gfx/gl.c b/gfx/gl.c index da29fb4f9e..b70cf935ff 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -26,6 +26,7 @@ #include #include #include "general.h" +#include "config.h" #ifdef HAVE_CG @@ -403,6 +404,7 @@ static void* gl_init(video_info_t *video, const input_driver_t **input) cg_active = false; if (strlen(g_settings.video.cg_shader_path) > 0) { + SSNES_LOG("Loading Cg file: %s\n", g_settings.video.cg_shader_path); gl->cgCtx = cgCreateContext(); if (gl->cgCtx == NULL) { From 73203b75c17ec5aec7e929604a678081b2bc9e16 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 13:54:49 +0100 Subject: [PATCH 37/47] Dynamic loading of libsnes. --- Makefile | 6 ++- dynamic.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++ dynamic.h | 54 +++++++++++++++++++ file.c | 13 ++--- general.h | 2 + qb/config.libs.sh | 4 +- settings.c | 5 ++ ssnes.c | 34 +++++++----- 8 files changed, 228 insertions(+), 22 deletions(-) create mode 100644 dynamic.c create mode 100644 dynamic.h diff --git a/Makefile b/Makefile index 33598ae5dd..39fd4a4c5e 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ include config.mk TARGET = ssnes -OBJ = ssnes.o file.o driver.o conf/config_file.o settings.o +OBJ = ssnes.o file.o driver.o conf/config_file.o settings.o dynamic.o LIBS = -lsamplerate $(libsnes) @@ -43,6 +43,10 @@ ifeq ($(HAVE_FILTER), 1) OBJ += hqflt/snes_ntsc/snes_ntsc.o endif +ifeq ($(HAVE_DL), 1) + LIBS += -ldl +endif + CFLAGS = -Wall -O3 -std=gnu99 -I. all: $(TARGET) config.mk diff --git a/dynamic.c b/dynamic.c new file mode 100644 index 0000000000..d819887c48 --- /dev/null +++ b/dynamic.c @@ -0,0 +1,132 @@ +/* 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 . + */ + +#include "dynamic.h" +#include "general.h" +#include +#include "config.h" + +#ifdef HAVE_DL +#include + +#define SYM(x) do { \ + p##x = dlsym(lib_handle, #x); \ + if (p##x == NULL) { SSNES_ERR("Failed to load symbol: \"%s\"\n", #x); exit(1); } \ +} while(0) + +#endif + +static void *lib_handle = NULL; + +void (*psnes_init)(void); + +void (*psnes_set_video_refresh)(snes_video_refresh_t); +void (*psnes_set_audio_sample)(snes_audio_sample_t); +void (*psnes_set_input_poll)(snes_input_poll_t); +void (*psnes_set_input_state)(snes_input_state_t); + +void (*psnes_run)(void); + +unsigned (*psnes_library_revision_minor)(void); +unsigned (*psnes_library_revision_major)(void); + +bool (*psnes_load_cartridge_normal)(const char*, const uint8_t*, unsigned); + +unsigned (*psnes_serialize_size)(void); +bool (*psnes_serialize)(uint8_t*, unsigned); +bool (*psnes_unserialize)(const uint8_t*, unsigned); + +void (*psnes_set_cartridge_basename)(const char*); + +uint8_t* (*psnes_get_memory_data)(unsigned); +unsigned (*psnes_get_memory_size)(unsigned); + +void (*psnes_unload_cartridge)(void); +void (*psnes_term)(void); + +#ifdef HAVE_DL +static void load_dynamic(void) +{ + lib_handle = dlopen(g_settings.libsnes, RTLD_LAZY); + if (!lib_handle) + { + SSNES_ERR("Failed to open dynamic library: \"%s\"\n", g_settings.libsnes); + exit(1); + } + + SYM(snes_init); + SYM(snes_set_video_refresh); + SYM(snes_set_audio_sample); + SYM(snes_set_input_poll); + SYM(snes_set_input_state); + SYM(snes_library_revision_minor); + SYM(snes_library_revision_major); + SYM(snes_run); + SYM(snes_load_cartridge_normal); + SYM(snes_serialize_size); + SYM(snes_serialize); + SYM(snes_unserialize); + SYM(snes_set_cartridge_basename); + SYM(snes_get_memory_data); + SYM(snes_get_memory_size); + SYM(snes_unload_cartridge); + SYM(snes_term); +} +#endif + +#define SSYM(x) do { \ + p##x = x; \ +} while(0) + +static void set_statics(void) +{ + SSYM(snes_init); + SSYM(snes_set_video_refresh); + SSYM(snes_set_audio_sample); + SSYM(snes_set_input_poll); + SSYM(snes_set_input_state); + SSYM(snes_library_revision_minor); + SSYM(snes_library_revision_major); + SSYM(snes_run); + SSYM(snes_load_cartridge_normal); + SSYM(snes_serialize_size); + SSYM(snes_serialize); + SSYM(snes_unserialize); + SSYM(snes_set_cartridge_basename); + SSYM(snes_get_memory_data); + SSYM(snes_get_memory_size); + SSYM(snes_unload_cartridge); + SSYM(snes_term); +} + +void init_dlsym(void) +{ +#ifdef HAVE_DL + if (strlen(g_settings.libsnes) > 0) + load_dynamic(); + else +#endif + set_statics(); +} + +void uninit_dlsym(void) +{ +#ifdef HAVE_DL + if (lib_handle) + dlclose(lib_handle); +#endif +} diff --git a/dynamic.h b/dynamic.h new file mode 100644 index 0000000000..a804da26bc --- /dev/null +++ b/dynamic.h @@ -0,0 +1,54 @@ +/* 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 . + */ + +#ifndef __DYNAMIC_H +#define __DYNAMIC_H + +#include +#include + +void init_dlsym(void); +void uninit_dlsym(void); + +extern void (*psnes_init)(void); + +extern void (*psnes_set_video_refresh)(snes_video_refresh_t); +extern void (*psnes_set_audio_sample)(snes_audio_sample_t); +extern void (*psnes_set_input_poll)(snes_input_poll_t); +extern void (*psnes_set_input_state)(snes_input_state_t); + +extern unsigned (*psnes_library_revision_minor)(void); +extern unsigned (*psnes_library_revision_major)(void); + +extern bool (*psnes_load_cartridge_normal)(const char*, const uint8_t*, unsigned); + +extern unsigned (*psnes_serialize_size)(void); +extern bool (*psnes_serialize)(uint8_t*, unsigned); +extern bool (*psnes_unserialize)(const uint8_t*, unsigned); + +extern void (*psnes_run)(void); + +extern void (*psnes_set_cartridge_basename)(const char*); + +extern uint8_t* (*psnes_get_memory_data)(unsigned); +extern unsigned (*psnes_get_memory_size)(unsigned); + +extern void (*psnes_unload_cartridge)(void); +extern void (*psnes_term)(void); + +#endif + diff --git a/file.c b/file.c index 6fc517592c..262eb4983e 100644 --- a/file.c +++ b/file.c @@ -21,6 +21,7 @@ #include #include #include +#include "dynamic.h" ssize_t read_file(FILE* file, void** buf) { @@ -101,7 +102,7 @@ void write_file(const char* path, uint8_t* data, size_t size) if ( file != NULL ) { SSNES_LOG("Saving state \"%s\". Size: %d bytes.\n", path, (int)size); - snes_serialize(data, size); + psnes_serialize(data, size); if ( fwrite(data, 1, size, file) != size ) SSNES_ERR("Did not save state properly.\n"); fclose(file); @@ -118,7 +119,7 @@ void load_state(const char* path, uint8_t* data, size_t size) if ( fread(data, 1, size, file) != size ) SSNES_ERR("Did not load state properly.\n"); fclose(file); - snes_unserialize(data, size); + psnes_unserialize(data, size); } else { @@ -136,8 +137,8 @@ void load_save_file(const char* path, int type) return; } - size_t size = snes_get_memory_size(type); - uint8_t *data = snes_get_memory_data(type); + size_t size = psnes_get_memory_size(type); + uint8_t *data = psnes_get_memory_data(type); if (size == 0 || !data) { @@ -158,8 +159,8 @@ void load_save_file(const char* path, int type) void save_file(const char* path, int type) { - size_t size = snes_get_memory_size(type); - uint8_t *data = snes_get_memory_data(type); + size_t size = psnes_get_memory_size(type); + uint8_t *data = psnes_get_memory_data(type); if ( data && size > 0 ) write_file(path, data, size); diff --git a/general.h b/general.h index 1a5a2acfd7..9ef3dfa4a7 100644 --- a/general.h +++ b/general.h @@ -66,6 +66,8 @@ struct settings int exit_emulator_key; float axis_threshold; } input; + + char libsnes[256]; }; struct global diff --git a/qb/config.libs.sh b/qb/config.libs.sh index 5dd6cf36f2..8eb41c6ed3 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -20,8 +20,10 @@ check_lib CG -lCg cgCreateContext check_lib SRC -lsamplerate src_callback_new +check_lib DL -ldl dlopen + # Creates config.mk. -VARS="ALSA OSS AL RSOUND ROAR GLFW FILTER CG" +VARS="ALSA OSS AL RSOUND ROAR GLFW FILTER CG DL" create_config_make config.mk $VARS create_config_header config.h $VARS diff --git a/settings.c b/settings.c index 307cf6b73b..42e0da94f6 100644 --- a/settings.c +++ b/settings.c @@ -255,6 +255,11 @@ void parse_config(void) strncpy(g_settings.audio.driver, tmp_str, sizeof(g_settings.audio.driver) - 1); free(tmp_str); } + if (config_get_string(conf, "libsnes_path", &tmp_str)) + { + strncpy(g_settings.libsnes, tmp_str, sizeof(g_settings.libsnes) - 1); + free(tmp_str); + } read_keybinds(conf); diff --git a/ssnes.c b/ssnes.c index 7ed7223f08..465cbc3be9 100644 --- a/ssnes.c +++ b/ssnes.c @@ -28,6 +28,7 @@ #include "file.h" #include "hqflt/filters.h" #include "general.h" +#include "dynamic.h" struct global g_extern = { .video_active = true, @@ -260,10 +261,10 @@ static void parse_input(int argc, char *argv[]) if (dst) { *dst = '\0'; - snes_set_cartridge_basename(tmp); + psnes_set_cartridge_basename(tmp); } else - snes_set_cartridge_basename(tmp); + psnes_set_cartridge_basename(tmp); SSNES_LOG("Opening file: \"%s\"\n", argv[optind]); g_extern.rom_file = fopen(argv[optind], "rb"); @@ -285,10 +286,13 @@ static void parse_input(int argc, char *argv[]) int main(int argc, char *argv[]) { - snes_init(); parse_input(argc, argv); parse_config(); + init_dlsym(); + + psnes_init(); + SSNES_LOG("Version of libsnes API: %u.%u\n", psnes_library_revision_major(), psnes_library_revision_minor()); void *rom_buf; ssize_t rom_len = 0; if ((rom_len = read_file(g_extern.rom_file, &rom_buf)) == -1) @@ -309,12 +313,12 @@ int main(int argc, char *argv[]) init_drivers(); - snes_set_video_refresh(video_frame); - snes_set_audio_sample(audio_sample); - snes_set_input_poll(input_poll); - snes_set_input_state(input_state); + psnes_set_video_refresh(video_frame); + psnes_set_audio_sample(audio_sample); + psnes_set_input_poll(input_poll); + psnes_set_input_state(input_state); - if (!snes_load_cartridge_normal(NULL, rom_buf, rom_len)) + if (!psnes_load_cartridge_normal(NULL, rom_buf, rom_len)) { SSNES_ERR("ROM file is not valid!\n"); goto error; @@ -322,7 +326,7 @@ int main(int argc, char *argv[]) free(rom_buf); - unsigned serial_size = snes_serialize_size(); + unsigned serial_size = psnes_serialize_size(); uint8_t *serial_data = malloc(serial_size); if (serial_data == NULL) { @@ -356,23 +360,25 @@ int main(int argc, char *argv[]) init_drivers(); } - snes_run(); + psnes_run(); } save_file(g_extern.savefile_name_srm, SNES_MEMORY_CARTRIDGE_RAM); save_file(savefile_name_rtc, SNES_MEMORY_CARTRIDGE_RTC); - snes_unload_cartridge(); - snes_term(); + psnes_unload_cartridge(); + psnes_term(); uninit_drivers(); free(serial_data); + uninit_dlsym(); return 0; error: - snes_unload_cartridge(); - snes_term(); + psnes_unload_cartridge(); + psnes_term(); uninit_drivers(); + uninit_dlsym(); return 1; } From 19e2b2768bef6062e5994af906aa4267ed063dbf Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 14:11:56 +0100 Subject: [PATCH 38/47] Fix up some issues with dynamic loading. --- Makefile | 2 +- dynamic.c | 1 + general.h | 1 + ssnes.c | 10 ++++------ ssnes.cfg | 3 +++ 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 39fd4a4c5e..5dde2d10b3 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ ifeq ($(HAVE_DL), 1) LIBS += -ldl endif -CFLAGS = -Wall -O3 -std=gnu99 -I. +CFLAGS = -Wall -O3 -g -std=gnu99 -I. all: $(TARGET) config.mk diff --git a/dynamic.c b/dynamic.c index d819887c48..0b359412f6 100644 --- a/dynamic.c +++ b/dynamic.c @@ -61,6 +61,7 @@ void (*psnes_term)(void); #ifdef HAVE_DL static void load_dynamic(void) { + SSNES_LOG("Loading dynamic libsnes from: \"%s\"\n", g_settings.libsnes); lib_handle = dlopen(g_settings.libsnes, RTLD_LAZY); if (!lib_handle) { diff --git a/general.h b/general.h index 9ef3dfa4a7..af97152d12 100644 --- a/general.h +++ b/general.h @@ -80,6 +80,7 @@ struct global FILE *rom_file; char savefile_name_srm[256]; char config_path[256]; + char basename[256]; }; void parse_config(void); diff --git a/ssnes.c b/ssnes.c index 465cbc3be9..8cbac9190e 100644 --- a/ssnes.c +++ b/ssnes.c @@ -259,12 +259,8 @@ static void parse_input(int argc, char *argv[]) strcpy(tmp, argv[optind]); char *dst = strrchr(tmp, '.'); if (dst) - { *dst = '\0'; - psnes_set_cartridge_basename(tmp); - } - else - psnes_set_cartridge_basename(tmp); + strncpy(g_extern.basename, tmp, sizeof(g_extern.basename) - 1); SSNES_LOG("Opening file: \"%s\"\n", argv[optind]); g_extern.rom_file = fopen(argv[optind], "rb"); @@ -288,10 +284,12 @@ int main(int argc, char *argv[]) { parse_input(argc, argv); parse_config(); - init_dlsym(); psnes_init(); + if (strlen(g_extern.basename) > 0) + psnes_set_cartridge_basename(g_extern.basename); + SSNES_LOG("Version of libsnes API: %u.%u\n", psnes_library_revision_major(), psnes_library_revision_minor()); void *rom_buf; ssize_t rom_len = 0; diff --git a/ssnes.cfg b/ssnes.cfg index f2c70d5a7d..b9d5f9aaba 100644 --- a/ssnes.cfg +++ b/ssnes.cfg @@ -1,5 +1,8 @@ ##### Config file for SSNES +## If enabled, load libsnes from a dynamic location. +# libsnes_path = "/path/to/libsnes.so" + #### Video # Windowed xscale and yscale (Real x res: 296 * xscale, real y scale: 224 * xscale) From 7e9a2a6e23f73eb21ab75ca936e6619ce5f44b5c Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 14:26:12 +0100 Subject: [PATCH 39/47] Should fix up dynamic loading by disabling internal link of the library as well... --- Makefile | 6 ++++-- dynamic.c | 17 ++++++++++++----- qb/config.libs.sh | 4 ++-- qb/config.params.sh | 1 + 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 5dde2d10b3..6f3e3a5372 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ TARGET = ssnes OBJ = ssnes.o file.o driver.o conf/config_file.o settings.o dynamic.o -LIBS = -lsamplerate $(libsnes) +LIBS = -lsamplerate ifeq ($(HAVE_RSOUND), 1) OBJ += audio/rsound.o @@ -43,8 +43,10 @@ ifeq ($(HAVE_FILTER), 1) OBJ += hqflt/snes_ntsc/snes_ntsc.o endif -ifeq ($(HAVE_DL), 1) +ifeq ($(HAVE_DYNAMIC), 1) LIBS += -ldl +else + LIBS += $(libsnes) endif CFLAGS = -Wall -O3 -g -std=gnu99 -I. diff --git a/dynamic.c b/dynamic.c index 0b359412f6..af87e0d027 100644 --- a/dynamic.c +++ b/dynamic.c @@ -20,7 +20,7 @@ #include #include "config.h" -#ifdef HAVE_DL +#ifdef HAVE_DYNAMIC #include #define SYM(x) do { \ @@ -58,7 +58,7 @@ unsigned (*psnes_get_memory_size)(unsigned); void (*psnes_unload_cartridge)(void); void (*psnes_term)(void); -#ifdef HAVE_DL +#ifdef HAVE_DYNAMIC static void load_dynamic(void) { SSNES_LOG("Loading dynamic libsnes from: \"%s\"\n", g_settings.libsnes); @@ -93,6 +93,7 @@ static void load_dynamic(void) p##x = x; \ } while(0) +#ifndef HAVE_DYNAMIC static void set_statics(void) { SSYM(snes_init); @@ -113,20 +114,26 @@ static void set_statics(void) SSYM(snes_unload_cartridge); SSYM(snes_term); } +#endif void init_dlsym(void) { -#ifdef HAVE_DL +#ifdef HAVE_DYNAMIC if (strlen(g_settings.libsnes) > 0) load_dynamic(); else -#endif + { + SSNES_ERR("This binary is built to use runtime dynamic binding of libsnes. Set libsnes_path in config to load a libsnes library dynamically.\n"); + exit(1); + } +#else set_statics(); +#endif } void uninit_dlsym(void) { -#ifdef HAVE_DL +#ifdef HAVE_DYNAMIC if (lib_handle) dlclose(lib_handle); #endif diff --git a/qb/config.libs.sh b/qb/config.libs.sh index 8eb41c6ed3..3ff699b50f 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -20,10 +20,10 @@ check_lib CG -lCg cgCreateContext check_lib SRC -lsamplerate src_callback_new -check_lib DL -ldl dlopen +check_lib DYNAMIC -ldl dlopen # Creates config.mk. -VARS="ALSA OSS AL RSOUND ROAR GLFW FILTER CG DL" +VARS="ALSA OSS AL RSOUND ROAR GLFW FILTER CG DYNAMIC" create_config_make config.mk $VARS create_config_header config.h $VARS diff --git a/qb/config.params.sh b/qb/config.params.sh index 768550b26b..3bf0d3305e 100644 --- a/qb/config.params.sh +++ b/qb/config.params.sh @@ -7,6 +7,7 @@ PACKAGE_VERSION=0.1 # $1: Variable (HAVE_ALSA, HAVE_OSS, etc) # $2: Comment # $3: Default arg. auto implies that HAVE_ALSA will be set according to library checks later on. +add_command_line_enable DYNAMIC "Enable dynamic loading of libsnes library." no add_command_line_string LIBSNES "libsnes library used" "-lsnes" add_command_line_enable FILTER "Disable CPU filter support" yes add_command_line_enable CG "Enable CG shader support" auto From 79e0429cf5482f3ea618aa8ee44eae30420ef3d9 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 14:27:55 +0100 Subject: [PATCH 40/47] Do not check for libsnes if we're building dynamic binary. --- qb/config.libs.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/qb/config.libs.sh b/qb/config.libs.sh index 3ff699b50f..a94db0fc9c 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -3,9 +3,11 @@ check_switch_c C99 -std=gnu99 check_critical C99 "Cannot find C99 compatible compiler." -check_lib_cxx SNES $LIBSNES snes_init -ldl -check_critical SNES "Cannot find libsnes." -add_define_make libsnes $LIBSNES +if [ $HAVE_DYNAMIC != yes ]; then + check_lib_cxx SNES $LIBSNES snes_init -ldl + check_critical SNES "Cannot find libsnes." + add_define_make libsnes $LIBSNES +fi check_lib ALSA -lasound snd_pcm_open check_header OSS sys/soundcard.h From 18fe25075fb16abafe07a63f3880a6b3978f092d Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 30 Dec 2010 17:49:06 +0100 Subject: [PATCH 41/47] Remove lingering debug message --- gfx/gl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/gfx/gl.c b/gfx/gl.c index b70cf935ff..3e9b38c351 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -420,7 +420,6 @@ static void* gl_init(video_info_t *video, const input_driver_t **input) } cgGLSetOptimalOptions(gl->cgFProf); cgGLSetOptimalOptions(gl->cgVProf); - puts(g_settings.video.cg_shader_path); gl->cgFPrg = cgCreateProgramFromFile(gl->cgCtx, CG_SOURCE, g_settings.video.cg_shader_path, gl->cgFProf, "main_fragment", 0); gl->cgVPrg = cgCreateProgramFromFile(gl->cgCtx, CG_SOURCE, g_settings.video.cg_shader_path, gl->cgVProf, "main_vertex", 0); if (gl->cgFPrg == NULL || gl->cgVPrg == NULL) From 161610c7a628d3a3100e5169ec291dfbf4f88600 Mon Sep 17 00:00:00 2001 From: Themaister Date: Fri, 31 Dec 2010 03:00:19 +0100 Subject: [PATCH 42/47] Add some more glfw key maps. --- settings.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/settings.c b/settings.c index 42e0da94f6..015e885a51 100644 --- a/settings.c +++ b/settings.c @@ -276,6 +276,7 @@ struct bind_map int snes_key; }; +// Big and nasty bind map... :) static const struct bind_map bind_maps[2][13] = { { { "input_player1_a", "input_player1_a_btn", NULL, SNES_DEVICE_ID_JOYPAD_A }, @@ -322,6 +323,9 @@ static const struct glfw_map glfw_map[] = { { "up", GLFW_KEY_UP }, { "down", GLFW_KEY_DOWN }, { "enter", GLFW_KEY_ENTER }, + { "tab", GLFW_KEY_TAB }, + { "insert", GLFW_KEY_INSERT }, + { "del", GLFW_KEY_DEL }, { "rshift", GLFW_KEY_RSHIFT }, { "shift", GLFW_KEY_LSHIFT }, { "ctrl", GLFW_KEY_LCTRL }, From b47f58c33814cf5361cd15709b035abdd8a57a7a Mon Sep 17 00:00:00 2001 From: Themaister Date: Sat, 1 Jan 2011 03:53:30 +0100 Subject: [PATCH 43/47] Add Jack audio driver. --- Makefile | 4 + audio/jack.c | 292 ++++++++++++++++++++++++++++++++++++++++++++++ config.def.h | 1 + driver.c | 3 + driver.h | 1 + dynamic.c | 2 + qb/config.libs.sh | 3 +- 7 files changed, 305 insertions(+), 1 deletion(-) create mode 100644 audio/jack.c diff --git a/Makefile b/Makefile index 6f3e3a5372..3972d52e75 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,10 @@ ifeq ($(HAVE_AL), 1) OBJ += audio/openal.o LIBS += -lopenal endif +ifeq ($(HAVE_JACK),1) + OBJ += audio/jack.o + LIBS += -ljack +endif ifeq ($(HAVE_GLFW), 1) OBJ += gfx/gl.o diff --git a/audio/jack.c b/audio/jack.c new file mode 100644 index 0000000000..cb8266118c --- /dev/null +++ b/audio/jack.c @@ -0,0 +1,292 @@ +/* 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 . + */ + + +#include "driver.h" +#include +#include "general.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define FRAMES(x) (x / (sizeof(int16_t) * 2)) +#define SAMPLES(x) (x / sizeof(int16_t)) + +typedef struct jack +{ + jack_client_t *client; + jack_port_t *ports[2]; + jack_ringbuffer_t *buffer[2]; + volatile bool shutdown; + bool nonblock; + + pthread_cond_t cond; + pthread_mutex_t cond_lock; +} jack_t; + +static int process_cb(jack_nframes_t nframes, void *data) +{ + jack_t *jd = data; + if (nframes <= 0) + { + pthread_cond_signal(&jd->cond); + return 0; + } + + jack_nframes_t avail[2]; + avail[0] = jack_ringbuffer_read_space(jd->buffer[0]); + avail[1] = jack_ringbuffer_read_space(jd->buffer[1]); + jack_nframes_t min_avail = FRAMES((avail[0] < avail[1]) ? avail[0] : avail[1]); + + if (min_avail > nframes) + min_avail = nframes; + + //static int underrun = 0; + //if (min_avail < nframes) + //{ + // fprintf(stderr, "underrun count: %d\n", underrun++); + // fprintf(stderr, "required %d frames, got %d.\n", (int)nframes, (int)min_avail); + //} + + for (int i = 0; i < 2; i++) + { + jack_default_audio_sample_t *out = jack_port_get_buffer(jd->ports[i], nframes); + assert(out); + jack_ringbuffer_read(jd->buffer[i], (char*)out, min_avail * sizeof(jack_default_audio_sample_t)); + + for (jack_nframes_t f = min_avail; f < nframes; f++) + { + out[f] = 0.0f; + } + } + pthread_cond_signal(&jd->cond); + return 0; +} + +static void shutdown_cb(void *data) +{ + jack_t *jd = data; + jd->shutdown = true; + pthread_cond_signal(&jd->cond); +} + +static inline void s16_to_float(jack_default_audio_sample_t * restrict out, const int16_t * restrict in, size_t samples) +{ + for (int i = 0; i < samples; i++) + out[i] = (float)in[i] / 0x8000; +} + +static void parse_ports(const char **dest_ports, const char **jports) +{ + int parsed = 0; + + const char *con = strtok(g_settings.audio.device, ","); + if (con) + dest_ports[parsed++] = con; + con = strtok(NULL, ","); + if (con) + dest_ports[parsed++] = con; + + for (int i = parsed; i < 2; i++) + dest_ports[i] = jports[i]; +} + +#define JACK_BUFFER_SIZE_MIN_FRAMES 128 +static void* __jack_init(const char* device, int rate, int latency) +{ + jack_t *jd = calloc(1, sizeof(jack_t)); + if ( jd == NULL ) + return NULL; + + const char **jports = NULL; + + jd->client = jack_client_open("SSNES", JackNullOption, NULL); + if (jd->client == NULL) + goto error; + + g_settings.audio.out_rate = jack_get_sample_rate(jd->client); + + jack_set_process_callback(jd->client, process_cb, jd); + jack_on_shutdown(jd->client, shutdown_cb, jd); + + jd->ports[0] = jack_port_register(jd->client, "left", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); + jd->ports[1] = jack_port_register(jd->client, "right", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); + if (jd->ports[0] == NULL || jd->ports[1] == NULL) + { + SSNES_ERR("Failed to register ports.\n"); + goto error; + } + + jack_nframes_t bufsize; + jack_nframes_t jack_bufsize = jack_get_buffer_size(jd->client); + + bufsize = (latency * g_settings.audio.out_rate / 1000 + 1) > jack_bufsize ? (latency * g_settings.audio.out_rate / 1000 + 1) : jack_bufsize; + bufsize *= sizeof(jack_default_audio_sample_t); + + //fprintf(stderr, "jack buffer size: %d\n", (int)bufsize); + for (int i = 0; i < 2; i++) + { + jd->buffer[i] = jack_ringbuffer_create(bufsize); + if (jd->buffer[i] == NULL) + { + SSNES_ERR("Failed to create buffers.\n"); + goto error; + } + } + + const char *dest_ports[2]; + jports = jack_get_ports(jd->client, NULL, NULL, JackPortIsPhysical | JackPortIsInput); + if (jports == NULL) + { + SSNES_ERR("Failed to get ports.\n"); + goto error; + } + + parse_ports(dest_ports, jports); + + if (jack_activate(jd->client) < 0) + { + SSNES_ERR("Failed to activate Jack...\n"); + goto error; + } + + for (int i = 0; i < 2; i++) + { + if (jack_connect(jd->client, jack_port_name(jd->ports[i]), dest_ports[i])) + { + SSNES_ERR("Failed to connect to Jack port.\n"); + goto error; + } + } + + pthread_cond_init(&jd->cond, NULL); + pthread_mutex_init(&jd->cond_lock, NULL); + + + jack_free(jports); + return jd; + +error: + if (jports != NULL) + jack_free(jports); + return NULL; +} + +static size_t write_buffer(jack_t *jd, const void *buf, size_t size) +{ + //fprintf(stderr, "write_buffer: size: %zu\n", size); + // Convert our data to float, deinterleave and write. + jack_default_audio_sample_t out_buffer[size / sizeof(int16_t)]; + jack_default_audio_sample_t out_deinterleaved_buffer[2][FRAMES(size)]; + s16_to_float(out_buffer, buf, SAMPLES(size)); + + for (int i = 0; i < 2; i++) + for (size_t j = 0; j < FRAMES(size); j++) + out_deinterleaved_buffer[i][j] = out_buffer[j * 2 + i]; + + for(;;) + { + if (jd->shutdown) + return 0; + + size_t avail[2]; + avail[0] = jack_ringbuffer_write_space(jd->buffer[0]); + avail[1] = jack_ringbuffer_write_space(jd->buffer[1]); + size_t min_avail = avail[0] < avail[1] ? avail[0] : avail[1]; + + if (jd->nonblock && min_avail < FRAMES(size) * sizeof(jack_default_audio_sample_t)) + return 0; + + //fprintf(stderr, "Write avail is: %d\n", (int)min_avail); + if (min_avail >= FRAMES(size) * sizeof(jack_default_audio_sample_t)) + break; + + pthread_mutex_lock(&jd->cond_lock); + pthread_cond_wait(&jd->cond, &jd->cond_lock); + pthread_mutex_unlock(&jd->cond_lock); + } + + for (int i = 0; i < 2; i++) + jack_ringbuffer_write(jd->buffer[i], (const char*)out_deinterleaved_buffer[i], FRAMES(size) * sizeof(jack_default_audio_sample_t)); + return size; +} + +static ssize_t __jack_write(void* data, const void* buf, size_t size) +{ + jack_t *jd = data; + + return write_buffer(jd, buf, size); +} + +static bool __jack_stop(void *data) +{ + (void)data; + return true; +} + +static void __jack_set_nonblock_state(void *data, bool state) +{ + jack_t *jd = data; + jd->nonblock = state; +} + +static bool __jack_start(void *data) +{ + (void)data; + return true; +} + +static void __jack_free(void *data) +{ + jack_t *jd = data; + + if (jd->client != NULL) + { + jack_deactivate(jd->client); + jack_client_close(jd->client); + } + + for (int i = 0; i < 2; i++) + if (jd->buffer[i] != NULL) + jack_ringbuffer_free(jd->buffer[i]); + + pthread_mutex_destroy(&jd->cond_lock); + pthread_cond_destroy(&jd->cond); + free(jd); +} + +const audio_driver_t audio_jack = { + .init = __jack_init, + .write = __jack_write, + .stop = __jack_stop, + .start = __jack_start, + .set_nonblock_state = __jack_set_nonblock_state, + .free = __jack_free, + .ident = "jack" +}; + + + + + + diff --git a/config.def.h b/config.def.h index 8db9455dcd..d2ce444381 100644 --- a/config.def.h +++ b/config.def.h @@ -37,6 +37,7 @@ #define AUDIO_ALSA 3 #define AUDIO_ROAR 4 #define AUDIO_AL 5 +#define AUDIO_JACK 6 //////////////////////// #define VIDEO_DEFAULT_DRIVER VIDEO_GL diff --git a/driver.c b/driver.c index c1d451906f..4e694af930 100644 --- a/driver.c +++ b/driver.c @@ -39,6 +39,9 @@ static const audio_driver_t *audio_drivers[] = { #ifdef HAVE_ROAR &audio_roar, #endif +#ifdef HAVE_JACK + &audio_jack, +#endif }; static const video_driver_t *video_drivers[] = { diff --git a/driver.h b/driver.h index 651dd3cf9b..f695746cd3 100644 --- a/driver.h +++ b/driver.h @@ -106,6 +106,7 @@ extern const audio_driver_t audio_oss; extern const audio_driver_t audio_alsa; extern const audio_driver_t audio_roar; extern const audio_driver_t audio_openal; +extern const audio_driver_t audio_jack; extern const video_driver_t video_gl; //////////////////////////////////////////////// diff --git a/dynamic.c b/dynamic.c index af87e0d027..5c8ff14ceb 100644 --- a/dynamic.c +++ b/dynamic.c @@ -30,7 +30,9 @@ #endif +#ifdef HAVE_DYNAMIC static void *lib_handle = NULL; +#endif void (*psnes_init)(void); diff --git a/qb/config.libs.sh b/qb/config.libs.sh index a94db0fc9c..a01eaf03d9 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -14,6 +14,7 @@ check_header OSS sys/soundcard.h check_lib AL -lopenal alcOpenDevice check_lib RSOUND -lrsound rsd_init check_lib ROAR -lroar roar_vs_new +check_lib JACK -ljack jack_client_open check_lib GLFW -lglfw glfwInit check_critical GLFW "Cannot find GLFW library." @@ -25,7 +26,7 @@ check_lib SRC -lsamplerate src_callback_new check_lib DYNAMIC -ldl dlopen # Creates config.mk. -VARS="ALSA OSS AL RSOUND ROAR GLFW FILTER CG DYNAMIC" +VARS="ALSA OSS AL RSOUND ROAR JACK GLFW FILTER CG DYNAMIC" create_config_make config.mk $VARS create_config_header config.h $VARS From 5f69145be25011aa0127c2ee79174ba35d0c5385 Mon Sep 17 00:00:00 2001 From: Themaister Date: Sat, 1 Jan 2011 04:50:35 +0100 Subject: [PATCH 44/47] Fix some issues with jack driver. --- audio/jack.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/audio/jack.c b/audio/jack.c index cb8266118c..01ae1c9ef6 100644 --- a/audio/jack.c +++ b/audio/jack.c @@ -56,7 +56,7 @@ static int process_cb(jack_nframes_t nframes, void *data) jack_nframes_t avail[2]; avail[0] = jack_ringbuffer_read_space(jd->buffer[0]); avail[1] = jack_ringbuffer_read_space(jd->buffer[1]); - jack_nframes_t min_avail = FRAMES((avail[0] < avail[1]) ? avail[0] : avail[1]); + jack_nframes_t min_avail = ((avail[0] < avail[1]) ? avail[0] : avail[1]) / sizeof(jack_default_audio_sample_t); if (min_avail > nframes) min_avail = nframes; @@ -64,7 +64,7 @@ static int process_cb(jack_nframes_t nframes, void *data) //static int underrun = 0; //if (min_avail < nframes) //{ - // fprintf(stderr, "underrun count: %d\n", underrun++); + // SSNES_LOG("JACK: Underrun count: %d\n", underrun++); // fprintf(stderr, "required %d frames, got %d.\n", (int)nframes, (int)min_avail); //} @@ -111,7 +111,6 @@ static void parse_ports(const char **dest_ports, const char **jports) dest_ports[i] = jports[i]; } -#define JACK_BUFFER_SIZE_MIN_FRAMES 128 static void* __jack_init(const char* device, int rate, int latency) { jack_t *jd = calloc(1, sizeof(jack_t)); @@ -140,7 +139,7 @@ static void* __jack_init(const char* device, int rate, int latency) jack_nframes_t bufsize; jack_nframes_t jack_bufsize = jack_get_buffer_size(jd->client); - bufsize = (latency * g_settings.audio.out_rate / 1000 + 1) > jack_bufsize ? (latency * g_settings.audio.out_rate / 1000 + 1) : jack_bufsize; + bufsize = (latency * g_settings.audio.out_rate / 1000) > jack_bufsize * 2 ? (latency * g_settings.audio.out_rate / 1000) : jack_bufsize * 2; bufsize *= sizeof(jack_default_audio_sample_t); //fprintf(stderr, "jack buffer size: %d\n", (int)bufsize); @@ -214,12 +213,19 @@ static size_t write_buffer(jack_t *jd, const void *buf, size_t size) avail[1] = jack_ringbuffer_write_space(jd->buffer[1]); size_t min_avail = avail[0] < avail[1] ? avail[0] : avail[1]; - if (jd->nonblock && min_avail < FRAMES(size) * sizeof(jack_default_audio_sample_t)) - return 0; - - //fprintf(stderr, "Write avail is: %d\n", (int)min_avail); - if (min_avail >= FRAMES(size) * sizeof(jack_default_audio_sample_t)) + if (jd->nonblock) + { + if (min_avail < FRAMES(size) * sizeof(jack_default_audio_sample_t)) + size = min_avail * 2 * sizeof(int16_t) / sizeof(jack_default_audio_sample_t); break; + } + + else + { + //fprintf(stderr, "Write avail is: %d\n", (int)min_avail); + if (min_avail >= FRAMES(size) * sizeof(jack_default_audio_sample_t)) + break; + } pthread_mutex_lock(&jd->cond_lock); pthread_cond_wait(&jd->cond, &jd->cond_lock); @@ -260,6 +266,8 @@ static void __jack_free(void *data) { jack_t *jd = data; + jd->shutdown = true; + if (jd->client != NULL) { jack_deactivate(jd->client); From aa4a6a4a046a1edbf88d9c6b52e43830c0fba491 Mon Sep 17 00:00:00 2001 From: Themaister Date: Sat, 1 Jan 2011 13:59:44 +0100 Subject: [PATCH 45/47] Additional fixes for quickbuild. --- qb/config.params.sh | 1 + qb/qb.params.sh | 17 +++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/qb/config.params.sh b/qb/config.params.sh index 3bf0d3305e..34dc9a88d2 100644 --- a/qb/config.params.sh +++ b/qb/config.params.sh @@ -16,3 +16,4 @@ add_command_line_enable OSS "Enable OSS support" auto 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 diff --git a/qb/qb.params.sh b/qb/qb.params.sh index 74ad6645fa..231310d8e5 100644 --- a/qb/qb.params.sh +++ b/qb/qb.params.sh @@ -91,16 +91,17 @@ parse_input() while [ ! -z "$1" ] do - prefix="`echo $1 | sed -e 's|^--prefix=\(\S\S*\)$|\1|' -e 's|\(\S\S*\)/|\1|'`" - - if [ "$prefix" != "$1" ]; then - PREFIX="$prefix" - shift - continue - fi - + case "$1" in + --prefix=*) + prefix="`echo $1 | sed -e 's|^--prefix=\(\S\S*\)$|\1|' -e 's|\(\S\S*\)/$|\1|'`" + + if [ "$prefix" != "$1" ]; then + PREFIX="$prefix" + fi + ;; + --enable-*) enable=`echo $1 | sed 's|^--enable-||'` if [ -z "`echo $COMMAND_LINE_OPTS_ENABLE | grep -i $enable`" ]; then From 840cfee6604f6c5583bb89dfe79f400fd24dde55 Mon Sep 17 00:00:00 2001 From: Themaister Date: Sat, 1 Jan 2011 16:03:15 +0100 Subject: [PATCH 46/47] Update readme to reflect the new changes --- README.md | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index ab32262042..446165946e 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,7 @@ This enables the possibility of custom front-ends for the emulator. # Philosophy SSNES attempts to be very small and lean, while still having all the useful core features expected from an emulator. -It is close in spirit to suckless' DWM, in that configuring the emulator requires a recompile. -The configuration is done through editing a C header file. -C programming skills are not necessary to configure it (no programming involved), but some basic programming experience might be needed. +It is used through command-line. # Dependencies @@ -33,6 +31,7 @@ SSNES needs one of these audio driver libraries: - RoarAudio - RSound - OpenAL + - JACK # Building libsnes @@ -46,17 +45,26 @@ SSNES needs one of these audio driver libraries: # Configuring -SSNES configuring is done through editing config.h and config.mk. -The default configs can be found in config.h.def and config.mk.def respectively. -Do note that you might have to edit config.mk if you edit driver and filter options! -By default, ALSA audio driver is assumed. +The default configuration is defined in config.def.h. +These can later be tweaked by using the ssnes config file. +A sample configuration file is installed to /etc/ssnes.cfg. +This is the system-wide config file. +Each user should create a config file in $XDG\_CONFIG\_HOME/ssnes. +The users only need to configure a certain option if the desired value deviates from the value defined in config.def.h. -Most options in config.h should be self-explanatory. To configure joypads, start up jstest /dev/input/js0 to determine which joypad buttons (and axis) to use. # Compiling and installing -The good old make && sudo make install should do the trick :) +As most packages, SSNES is built using the standard ./configure && make && make install +Do note that the build system is not autotools based, but resembles it. + +Notable options for ./configure: +--with-libsnes=: Normally libsnes is located with -lsnes, however, this can be overridden. +--enable-dynamic: Do not link to libsnes at compile time, but load libsnes dynamically at runtime. libsnes\_path in config file defines which library to load. Useful for development. + +Do note that these two options are mutually exclusive. + # Filters and Cg shader support @@ -67,3 +75,5 @@ Cg shaders are compiled at run-time, and shaders could be dropped in. All shaders share a common interface to pass some essential arguments such as texture size and viewport size. (Common for pixel art scalers) Some Cg shaders are included in hqflt/cg/ and could be used as an example. +While these shaders are Cg, they closely resemble the GLSL shaders found in bSNES shader pack, so porting them is trivial. + From 5c726f96449eeb5a192b5e068de9c98947c0cb80 Mon Sep 17 00:00:00 2001 From: Themaister Date: Sat, 1 Jan 2011 17:59:59 +0100 Subject: [PATCH 47/47] Move default config location --- README.md | 2 +- hqflt/cg/crt.cg | 2 +- settings.c | 4 ++-- ssnes.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 446165946e..a6ce0b1d0c 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ The default configuration is defined in config.def.h. These can later be tweaked by using the ssnes config file. A sample configuration file is installed to /etc/ssnes.cfg. This is the system-wide config file. -Each user should create a config file in $XDG\_CONFIG\_HOME/ssnes. +Each user should create a config file in $XDG\_CONFIG\_HOME/ssnes/ssnes.cfg. The users only need to configure a certain option if the desired value deviates from the value defined in config.def.h. To configure joypads, start up jstest /dev/input/js0 to determine which joypad buttons (and axis) to use. diff --git a/hqflt/cg/crt.cg b/hqflt/cg/crt.cg index ab89abc478..bee618ad38 100644 --- a/hqflt/cg/crt.cg +++ b/hqflt/cg/crt.cg @@ -52,7 +52,7 @@ output main_fragment(float2 texCoord : TEXCOORD0, uniform sampler2D decal : TEXU float2 rubyTextureSize = IN.texture_size; float2 xy = barrelDistortion(texCoord.xy); - float2 one = 0.999/rubyTextureSize; + float2 one = 1.0/rubyTextureSize; xy = xy + float2(0.0 , -0.5 * (phase + (1-phase) * rubyInputSize.y/rubyOutputSize.y) * one.y); float4 texels[8]; texels[0] = TEX2D(xy + float2(-one.x,0.0)); diff --git a/settings.c b/settings.c index 015e885a51..0288dd3dd6 100644 --- a/settings.c +++ b/settings.c @@ -120,9 +120,9 @@ void parse_config(void) const char *home = getenv("HOME"); if (xdg) { - char conf_path[strlen(xdg) + strlen("/ssnes ")]; + char conf_path[strlen(xdg) + strlen("/ssnes/ssnes.cfg ")]; strcpy(conf_path, xdg); - strcat(conf_path, "/ssnes"); + strcat(conf_path, "/ssnes/ssnes.cfg"); conf = config_file_new(conf_path); } else if (home) diff --git a/ssnes.c b/ssnes.c index 8cbac9190e..cc0c518b10 100644 --- a/ssnes.c +++ b/ssnes.c @@ -195,7 +195,7 @@ static void print_help(void) puts("Usage: ssnes [rom file] [-h/--help | -s/--save]"); puts("\t-h/--help: Show this help message"); puts("\t-s/--save: Path for save file (*.srm). Required when rom is input from stdin"); - puts("\t-c/--config: Path for config file. Defaults to $XDG_CONFIG_HOME/ssnes"); + puts("\t-c/--config: Path for config file. Defaults to $XDG_CONFIG_HOME/ssnes/ssnes.cfg"); puts("\t-v/--verbose: Verbose logging"); }