diff --git a/Makefile b/Makefile
index 5994b783a5..b7d63eef99 100644
--- a/Makefile
+++ b/Makefile
@@ -108,6 +108,12 @@ ifeq ($(HAVE_FREETYPE), 1)
DEFINES += $(FREETYPE_CFLAGS)
endif
+ifeq ($(HAVE_IMLIB), 1)
+ OBJ += gfx/image.o
+ LIBS += $(IMLIB_LIBS)
+ DEFINES += $(IMLIB_CFLAGS)
+endif
+
ifeq ($(HAVE_FFMPEG), 1)
OBJ += record/ffemu.o
LIBS += $(AVCODEC_LIBS) $(AVCORE_LIBS) $(AVFORMAT_LIBS) $(AVUTIL_LIBS) $(SWSCALE_LIBS)
diff --git a/gfx/image.c b/gfx/image.c
new file mode 100644
index 0000000000..500928f1b4
--- /dev/null
+++ b/gfx/image.c
@@ -0,0 +1,53 @@
+/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
+ * Copyright (C) 2010-2011 - 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 "image.h"
+#include
+#include
+#include
+#include
+
+// Imlib2 <3<3<3<3
+bool texture_image_load(const char *path, struct texture_image *out_img)
+{
+ Imlib_Image img;
+ img = imlib_load_image(path);
+ if (!img)
+ return false;
+
+ imlib_context_set_image(img);
+
+ out_img->width = imlib_image_get_width();
+ out_img->height = imlib_image_get_height();
+
+ size_t size = out_img->width * out_img->height * sizeof(uint32_t);
+ out_img->pixels = malloc(size);
+ if (!out_img->pixels)
+ {
+ imlib_free_image();
+ return false;
+ }
+
+ const uint32_t *read = imlib_image_get_data_for_reading_only();
+ // Convert ARGB -> RGBA.
+ for (unsigned i = 0; i < size / sizeof(uint32_t); i++)
+ out_img->pixels[i] = (read[i] >> 24) | (read[i] << 8);
+
+ imlib_free_image();
+ return true;
+}
diff --git a/gfx/image.h b/gfx/image.h
new file mode 100644
index 0000000000..e2644f65bf
--- /dev/null
+++ b/gfx/image.h
@@ -0,0 +1,34 @@
+/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
+ * Copyright (C) 2010-2011 - 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 __SSNES_IMAGE_H
+#define __SSNES_IMAGE_H
+
+#include
+#include
+
+struct texture_image
+{
+ unsigned width;
+ unsigned height;
+ uint32_t *pixels;
+};
+
+bool texture_image_load(const char *path, struct texture_image* img);
+
+
+#endif
diff --git a/gfx/shader_glsl.c b/gfx/shader_glsl.c
index 2576d4435e..89ee434f86 100644
--- a/gfx/shader_glsl.c
+++ b/gfx/shader_glsl.c
@@ -19,6 +19,11 @@
#include
#include "general.h"
#include "shader_glsl.h"
+#include "strl.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
#ifdef __APPLE__
#include
@@ -38,6 +43,11 @@
#include "gl_common.h"
+#ifdef HAVE_IMLIB
+#include "image.h"
+#endif
+
+
#ifdef __APPLE__
#define pglCreateProgram glCreateProgram
#define pglUseProgram glUseProgram
@@ -81,6 +91,7 @@ static PFNGLGETATTACHEDSHADERSPROC pglGetAttachedShaders = NULL;
#endif
#define MAX_PROGRAMS 16
+#define MAX_TEXTURES 4
enum filter_type
{
@@ -96,6 +107,10 @@ static struct gl_fbo_scale gl_scale[MAX_PROGRAMS];
static unsigned gl_num_programs = 0;
static unsigned active_index = 0;
+static GLuint gl_teximage[MAX_TEXTURES];
+static unsigned gl_teximage_cnt = 0;
+static char gl_teximage_uniforms[MAX_TEXTURES][64];
+
struct shader_program
{
char *vertex;
@@ -273,6 +288,86 @@ static bool get_xml_attrs(struct shader_program *prog, xmlNodePtr ptr)
return true;
}
+#ifdef HAVE_IMLIB
+static bool get_texture_image(const char *shader_path, xmlNodePtr ptr)
+{
+ bool linear = true;
+ xmlChar *filename = xmlGetProp(ptr, (const xmlChar*)"file");
+ xmlChar *filter = xmlGetProp(ptr, (const xmlChar*)"filter");
+ xmlChar *id = xmlGetProp(ptr, (const xmlChar*)"id");
+
+ if (!id)
+ {
+ SSNES_ERR("Could not find ID in texture.\n");
+ goto error;
+ }
+
+ if (!filename)
+ {
+ SSNES_ERR("Could not find filename in texture.\n");
+ goto error;
+ }
+
+ if (filter && strcmp((const char*)filter, "nearest") == 0)
+ linear = false;
+
+ char tex_path[256];
+ strlcpy(tex_path, shader_path, sizeof(tex_path));
+
+ char *last = strrchr(tex_path, '/');
+ if (!last) last = strrchr(tex_path, '\\');
+ if (last) last[1] = '\0';
+
+ strlcat(tex_path, (const char*)filename, sizeof(tex_path));
+
+ struct texture_image img;
+ SSNES_LOG("Loading texture image from: \"%s\" ...\n", tex_path);
+ if (!texture_image_load(tex_path, &img))
+ {
+ SSNES_ERR("Failed to load texture image from: \"%s\"\n", tex_path);
+ goto error;
+ }
+
+ strlcpy(gl_teximage_uniforms[gl_teximage_cnt], (const char*)id, sizeof(gl_teximage_uniforms[0]));
+
+ glGenTextures(1, &gl_teximage[gl_teximage_cnt]);
+ glActiveTexture(GL_TEXTURE0 + gl_teximage_cnt + 1);
+ glBindTexture(GL_TEXTURE_2D, gl_teximage[gl_teximage_cnt]);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR : GL_NEAREST);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, img.width);
+ glTexImage2D(GL_TEXTURE_2D,
+ 0, GL_RGBA, img.width, img.height, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, img.pixels);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ free(img.pixels);
+
+ xmlFree(filename);
+ xmlFree(id);
+ if (filter)
+ xmlFree(filter);
+
+ gl_teximage_cnt++;
+
+ return true;
+
+error:
+ if (filename)
+ xmlFree(filename);
+ if (filter)
+ xmlFree(filter);
+ if (filter)
+ xmlFree(id);
+ return false;
+}
+#endif
+
static unsigned get_xml_shaders(const char *path, struct shader_program *prog, size_t size)
{
LIBXML_TEST_VERSION;
@@ -354,6 +449,16 @@ static unsigned get_xml_shaders(const char *path, struct shader_program *prog, s
}
num++;
}
+#ifdef HAVE_IMLIB
+ else if (strcmp((const char*)cur->name, "texture") == 0)
+ {
+ if (!get_texture_image(path, cur))
+ {
+ SSNES_ERR("Texture image failed to load.\n");
+ goto error;
+ }
+ }
+#endif
}
if (num == 0)
@@ -587,6 +692,10 @@ void gl_glsl_deinit(void)
pglDeleteProgram(gl_program[i]);
}
+
+ glDeleteTextures(gl_teximage_cnt, gl_teximage);
+ gl_teximage_cnt = 0;
+ memset(gl_teximage_uniforms, 0, sizeof(gl_teximage_uniforms));
}
memset(gl_program, 0, sizeof(gl_program));
@@ -617,6 +726,12 @@ void gl_glsl_set_params(unsigned width, unsigned height,
location = pglGetUniformLocation(gl_program[active_index], "rubyFrameCount");
pglUniform1i(location, frame_count);
+
+ for (unsigned i = 0; i < gl_teximage_cnt; i++)
+ {
+ location = pglGetUniformLocation(gl_program[active_index], gl_teximage_uniforms[i]);
+ pglUniform1i(location, i + 1);
+ }
}
}
diff --git a/qb/config.libs.sh b/qb/config.libs.sh
index 0ddc03939e..a765ed6521 100644
--- a/qb/config.libs.sh
+++ b/qb/config.libs.sh
@@ -43,6 +43,7 @@ check_critical SDL "Cannot find SDL library."
check_lib CG -lCg cgCreateContext
check_pkgconf XML libxml-2.0
+check_pkgconf IMLIB imlib2
if [ $HAVE_FFMPEG != no ]; then
check_pkgconf AVCODEC libavcodec
@@ -64,7 +65,7 @@ check_lib XVIDEO -lXv XvShmCreateImage
check_lib STRL -lc strlcpy
# Creates config.mk and config.h.
-VARS="ALSA OSS AL RSOUND ROAR JACK PULSE SDL DYLIB CG XML DYNAMIC FFMPEG AVCODEC AVFORMAT AVCORE AVUTIL SWSCALE SRC CONFIGFILE FREETYPE XVIDEO NETPLAY FBO STRL"
+VARS="ALSA OSS AL RSOUND ROAR JACK PULSE SDL DYLIB CG XML IMLIB DYNAMIC FFMPEG AVCODEC AVFORMAT AVCORE AVUTIL SWSCALE SRC CONFIGFILE FREETYPE XVIDEO NETPLAY FBO STRL"
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 5b8a8706e6..93f8ee7106 100644
--- a/qb/config.params.sh
+++ b/qb/config.params.sh
@@ -26,3 +26,4 @@ add_command_line_enable JACK "Enable JACK support" auto
add_command_line_enable PULSE "Enable PulseAudio support" auto
add_command_line_enable FREETYPE "Enable FreeType support" auto
add_command_line_enable XVIDEO "Enable XVideo support" auto
+add_command_line_enable IMLIB "Enable imlib2 support" auto