Scaling filters in SDL
This commit is contained in:
parent
c03ccba8db
commit
d262dde71a
13
Makefile
13
Makefile
@ -43,7 +43,7 @@ endif
|
|||||||
# Set compilation and linkage flags based on target, platform and configuration
|
# Set compilation and linkage flags based on target, platform and configuration
|
||||||
|
|
||||||
CFLAGS += -Werror -Wall -std=gnu11 -ICore -D_GNU_SOURCE -DVERSION="$(VERSION)" -I. -D_USE_MATH_DEFINES
|
CFLAGS += -Werror -Wall -std=gnu11 -ICore -D_GNU_SOURCE -DVERSION="$(VERSION)" -I. -D_USE_MATH_DEFINES
|
||||||
SDL_LDFLAGS := -lSDL2
|
SDL_LDFLAGS := -lSDL2 -lGL
|
||||||
ifeq ($(PLATFORM),windows32)
|
ifeq ($(PLATFORM),windows32)
|
||||||
CFLAGS += -IWindows
|
CFLAGS += -IWindows
|
||||||
LDFLAGS += -lmsvcrt -lSDL2main -Wl,/MANIFESTFILE:NUL
|
LDFLAGS += -lmsvcrt -lSDL2main -Wl,/MANIFESTFILE:NUL
|
||||||
@ -56,7 +56,7 @@ SYSROOT := $(shell xcodebuild -sdk macosx -version Path 2> /dev/null)
|
|||||||
CFLAGS += -F/Library/Frameworks
|
CFLAGS += -F/Library/Frameworks
|
||||||
OCFLAGS += -x objective-c -fobjc-arc -Wno-deprecated-declarations -isysroot $(SYSROOT) -mmacosx-version-min=10.9
|
OCFLAGS += -x objective-c -fobjc-arc -Wno-deprecated-declarations -isysroot $(SYSROOT) -mmacosx-version-min=10.9
|
||||||
LDFLAGS += -framework AppKit -framework PreferencePanes -framework Carbon -framework QuartzCore
|
LDFLAGS += -framework AppKit -framework PreferencePanes -framework Carbon -framework QuartzCore
|
||||||
SDL_LDFLAGS := -F/Library/Frameworks -framework SDL2
|
SDL_LDFLAGS := -F/Library/Frameworks -framework SDL2 -framework OpenGL
|
||||||
endif
|
endif
|
||||||
CFLAGS += -Wno-deprecated-declarations
|
CFLAGS += -Wno-deprecated-declarations
|
||||||
ifeq ($(PLATFORM),windows32)
|
ifeq ($(PLATFORM),windows32)
|
||||||
@ -88,7 +88,7 @@ endif
|
|||||||
|
|
||||||
cocoa: $(BIN)/SameBoy.app
|
cocoa: $(BIN)/SameBoy.app
|
||||||
quicklook: $(BIN)/SameBoy.qlgenerator
|
quicklook: $(BIN)/SameBoy.qlgenerator
|
||||||
sdl: $(SDL_TARGET) $(BIN)/SDL/dmg_boot.bin $(BIN)/SDL/cgb_boot.bin $(BIN)/SDL/LICENSE $(BIN)/SDL/registers.sym $(BIN)/SDL/background.bmp
|
sdl: $(SDL_TARGET) $(BIN)/SDL/dmg_boot.bin $(BIN)/SDL/cgb_boot.bin $(BIN)/SDL/LICENSE $(BIN)/SDL/registers.sym $(BIN)/SDL/background.bmp $(BIN)/SDL/Shaders
|
||||||
bootroms: $(BIN)/BootROMs/cgb_boot.bin $(BIN)/BootROMs/dmg_boot.bin
|
bootroms: $(BIN)/BootROMs/cgb_boot.bin $(BIN)/BootROMs/dmg_boot.bin
|
||||||
tester: $(TESTER_TARGET) $(BIN)/tester/dmg_boot.bin $(BIN)/tester/cgb_boot.bin
|
tester: $(TESTER_TARGET) $(BIN)/tester/dmg_boot.bin $(BIN)/tester/cgb_boot.bin
|
||||||
all: cocoa sdl tester
|
all: cocoa sdl tester
|
||||||
@ -262,14 +262,21 @@ $(BIN)/SameBoy.app/Contents/Resources/%.bin: $(BOOTROMS_DIR)/%.bin
|
|||||||
cp -f $^ $@
|
cp -f $^ $@
|
||||||
|
|
||||||
$(BIN)/SDL/LICENSE: LICENSE
|
$(BIN)/SDL/LICENSE: LICENSE
|
||||||
|
-@$(MKDIR) -p $(dir $@)
|
||||||
cp -f $^ $@
|
cp -f $^ $@
|
||||||
|
|
||||||
$(BIN)/SDL/registers.sym: Misc/registers.sym
|
$(BIN)/SDL/registers.sym: Misc/registers.sym
|
||||||
|
-@$(MKDIR) -p $(dir $@)
|
||||||
cp -f $^ $@
|
cp -f $^ $@
|
||||||
|
|
||||||
$(BIN)/SDL/background.bmp: SDL/background.bmp
|
$(BIN)/SDL/background.bmp: SDL/background.bmp
|
||||||
|
-@$(MKDIR) -p $(dir $@)
|
||||||
cp -f $^ $@
|
cp -f $^ $@
|
||||||
|
|
||||||
|
$(BIN)/SDL/Shaders: Shaders
|
||||||
|
-@$(MKDIR) -p $(dir $@)
|
||||||
|
cp -rf $^ $@
|
||||||
|
|
||||||
# Boot ROMs
|
# Boot ROMs
|
||||||
|
|
||||||
$(BIN)/BootROMs/%.bin: BootROMs/%.asm
|
$(BIN)/BootROMs/%.bin: BootROMs/%.asm
|
||||||
|
130
SDL/gui.c
130
SDL/gui.c
@ -20,6 +20,31 @@ unsigned command_parameter;
|
|||||||
#define MODIFIER_NAME CTRL_STRING
|
#define MODIFIER_NAME CTRL_STRING
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
shader_t shader;
|
||||||
|
SDL_Rect rect;
|
||||||
|
|
||||||
|
void render_texture(void *pixels, void *previous)
|
||||||
|
{
|
||||||
|
if (renderer) {
|
||||||
|
if (pixels) {
|
||||||
|
SDL_UpdateTexture(texture, NULL, pixels, 160 * sizeof (uint32_t));
|
||||||
|
}
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
SDL_RenderCopy(renderer, texture, NULL, NULL);
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
static void *_pixels = NULL;
|
||||||
|
if (pixels) {
|
||||||
|
_pixels = pixels;
|
||||||
|
}
|
||||||
|
glClearColor(0, 0, 0, 1);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
render_bitmap_with_shader(&shader, _pixels, previous, rect.x, rect.y, rect.w, rect.h);
|
||||||
|
SDL_GL_SwapWindow(window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
configuration_t configuration =
|
configuration_t configuration =
|
||||||
{
|
{
|
||||||
{ SDL_SCANCODE_RIGHT,
|
{ SDL_SCANCODE_RIGHT,
|
||||||
@ -59,7 +84,7 @@ static const char *help[] ={
|
|||||||
void update_viewport(void)
|
void update_viewport(void)
|
||||||
{
|
{
|
||||||
int win_width, win_height;
|
int win_width, win_height;
|
||||||
SDL_GetWindowSize(window, &win_width, &win_height);
|
SDL_GL_GetDrawableSize(window, &win_width, &win_height);
|
||||||
double x_factor = win_width / 160.0;
|
double x_factor = win_width / 160.0;
|
||||||
double y_factor = win_height / 144.0;
|
double y_factor = win_height / 144.0;
|
||||||
|
|
||||||
@ -80,9 +105,15 @@ void update_viewport(void)
|
|||||||
unsigned new_width = x_factor * 160;
|
unsigned new_width = x_factor * 160;
|
||||||
unsigned new_height = y_factor * 144;
|
unsigned new_height = y_factor * 144;
|
||||||
|
|
||||||
SDL_Rect rect = (SDL_Rect){(win_width - new_width) / 2, (win_height - new_height) /2,
|
rect = (SDL_Rect){(win_width - new_width) / 2, (win_height - new_height) /2,
|
||||||
new_width, new_height};
|
new_width, new_height};
|
||||||
|
|
||||||
|
if (renderer) {
|
||||||
SDL_RenderSetViewport(renderer, &rect);
|
SDL_RenderSetViewport(renderer, &rect);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
glViewport(rect.x, rect.y, rect.w, rect.h);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Does NOT check for bounds! */
|
/* Does NOT check for bounds! */
|
||||||
@ -234,9 +265,7 @@ void cycle_scaling(unsigned index)
|
|||||||
configuration.scaling_mode = 0;
|
configuration.scaling_mode = 0;
|
||||||
}
|
}
|
||||||
update_viewport();
|
update_viewport();
|
||||||
SDL_RenderClear(renderer);
|
render_texture(NULL, NULL);
|
||||||
SDL_RenderCopy(renderer, texture, NULL, NULL);
|
|
||||||
SDL_RenderPresent(renderer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cycle_scaling_backwards(unsigned index)
|
void cycle_scaling_backwards(unsigned index)
|
||||||
@ -248,9 +277,7 @@ void cycle_scaling_backwards(unsigned index)
|
|||||||
configuration.scaling_mode--;
|
configuration.scaling_mode--;
|
||||||
}
|
}
|
||||||
update_viewport();
|
update_viewport();
|
||||||
SDL_RenderClear(renderer);
|
render_texture(NULL, NULL);
|
||||||
SDL_RenderCopy(renderer, texture, NULL, NULL);
|
|
||||||
SDL_RenderPresent(renderer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cycle_color_correction(unsigned index)
|
static void cycle_color_correction(unsigned index)
|
||||||
@ -273,6 +300,82 @@ static void cycle_color_correction_backwards(unsigned index)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct shader_name {
|
||||||
|
const char *file_name;
|
||||||
|
const char *display_name;
|
||||||
|
} shaders[] =
|
||||||
|
{
|
||||||
|
{"NearestNeighbor", "Nearest Neighbor"},
|
||||||
|
{"Bilinear", "Bilinear"},
|
||||||
|
{"SmoothBilinear", "Smooth Bilinear"},
|
||||||
|
{"Scale2x", "Scale2x"},
|
||||||
|
{"Scale4x", "Scale4x"},
|
||||||
|
{"AAScale2x", "Anti-aliased Scale2x"},
|
||||||
|
{"AAScale4x", "Anti-aliased Scale4x"},
|
||||||
|
{"HQ2x", "HQ2x"},
|
||||||
|
{"OmniScale", "OmniScale"},
|
||||||
|
{"OmniScaleLegacy", "OmniScale Legacy"},
|
||||||
|
{"AAOmniScaleLegacy", "AA OmniScale Legacy"},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void cycle_filter(unsigned index)
|
||||||
|
{
|
||||||
|
unsigned i = 0;
|
||||||
|
for (; i < sizeof(shaders) / sizeof(shaders[0]); i++) {
|
||||||
|
if (strcmp(shaders[i].file_name, configuration.filter) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
i += 1;
|
||||||
|
if (i >= sizeof(shaders) / sizeof(shaders[0])) {
|
||||||
|
i -= sizeof(shaders) / sizeof(shaders[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(configuration.filter, shaders[i].file_name);
|
||||||
|
free_shader(&shader);
|
||||||
|
if (!init_shader_with_name(&shader, configuration.filter)) {
|
||||||
|
init_shader_with_name(&shader, "NearestNeighbor");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cycle_filter_backwards(unsigned index)
|
||||||
|
{
|
||||||
|
unsigned i = 0;
|
||||||
|
for (; i < sizeof(shaders) / sizeof(shaders[0]); i++) {
|
||||||
|
if (strcmp(shaders[i].file_name, configuration.filter) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i -= 1;
|
||||||
|
if (i >= sizeof(shaders) / sizeof(shaders[0])) {
|
||||||
|
i = sizeof(shaders) / sizeof(shaders[0]) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(configuration.filter, shaders[i].file_name);
|
||||||
|
free_shader(&shader);
|
||||||
|
if (!init_shader_with_name(&shader, configuration.filter)) {
|
||||||
|
init_shader_with_name(&shader, "NearestNeighbor");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
const char *current_filter_name(unsigned index)
|
||||||
|
{
|
||||||
|
unsigned i = 0;
|
||||||
|
for (; i < sizeof(shaders) / sizeof(shaders[0]); i++) {
|
||||||
|
if (strcmp(shaders[i].file_name, configuration.filter) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == sizeof(shaders) / sizeof(shaders[0])) {
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return shaders[i].display_name;
|
||||||
|
}
|
||||||
|
|
||||||
static void return_to_root_menu(unsigned index)
|
static void return_to_root_menu(unsigned index)
|
||||||
{
|
{
|
||||||
@ -282,6 +385,7 @@ static void return_to_root_menu(unsigned index)
|
|||||||
|
|
||||||
static const struct menu_item graphics_menu[] = {
|
static const struct menu_item graphics_menu[] = {
|
||||||
{"Scaling Mode:", cycle_scaling, current_scaling_mode, cycle_scaling_backwards},
|
{"Scaling Mode:", cycle_scaling, current_scaling_mode, cycle_scaling_backwards},
|
||||||
|
{"Scaling Filter:", cycle_filter, current_filter_name, cycle_filter_backwards},
|
||||||
{"Color Correction:", cycle_color_correction, current_color_correction_mode, cycle_color_correction_backwards},
|
{"Color Correction:", cycle_color_correction, current_color_correction_mode, cycle_color_correction_backwards},
|
||||||
{"Back", return_to_root_menu},
|
{"Back", return_to_root_menu},
|
||||||
{NULL,}
|
{NULL,}
|
||||||
@ -399,6 +503,7 @@ static void detect_joypad_layout(unsigned index)
|
|||||||
static const struct menu_item joypad_menu[] = {
|
static const struct menu_item joypad_menu[] = {
|
||||||
{"Joypad:", cycle_joypads, current_joypad_name, cycle_joypads_backwards},
|
{"Joypad:", cycle_joypads, current_joypad_name, cycle_joypads_backwards},
|
||||||
{"Detect layout", detect_joypad_layout},
|
{"Detect layout", detect_joypad_layout},
|
||||||
|
{"Back", return_to_root_menu},
|
||||||
{NULL,}
|
{NULL,}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -510,9 +615,7 @@ void run_gui(bool is_running)
|
|||||||
case SDL_WINDOWEVENT: {
|
case SDL_WINDOWEVENT: {
|
||||||
if (event.window.event == SDL_WINDOWEVENT_RESIZED) {
|
if (event.window.event == SDL_WINDOWEVENT_RESIZED) {
|
||||||
update_viewport();
|
update_viewport();
|
||||||
SDL_RenderClear(renderer);
|
render_texture(NULL, NULL);
|
||||||
SDL_RenderCopy(renderer, texture, NULL, NULL);
|
|
||||||
SDL_RenderPresent(renderer);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -667,10 +770,7 @@ void run_gui(bool is_running)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_UpdateTexture(texture, NULL, pixels, 160 * sizeof (uint32_t));
|
render_texture(pixels, NULL);
|
||||||
SDL_RenderClear(renderer);
|
|
||||||
SDL_RenderCopy(renderer, texture, NULL, NULL);
|
|
||||||
SDL_RenderPresent(renderer);
|
|
||||||
}
|
}
|
||||||
} while (SDL_WaitEvent(&event));
|
} while (SDL_WaitEvent(&event));
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,13 @@
|
|||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
#include <Core/gb.h>
|
#include <Core/gb.h>
|
||||||
|
#include "shader.h"
|
||||||
|
|
||||||
extern SDL_Window *window;
|
extern SDL_Window *window;
|
||||||
extern SDL_Renderer *renderer;
|
extern SDL_Renderer *renderer;
|
||||||
extern SDL_Texture *texture;
|
extern SDL_Texture *texture;
|
||||||
extern SDL_PixelFormat *pixel_format;
|
extern SDL_PixelFormat *pixel_format;
|
||||||
|
extern shader_t shader;
|
||||||
|
|
||||||
enum scaling_mode {
|
enum scaling_mode {
|
||||||
GB_SDL_SCALING_ENTIRE_WINDOW,
|
GB_SDL_SCALING_ENTIRE_WINDOW,
|
||||||
@ -37,6 +39,8 @@ typedef struct {
|
|||||||
bool div_joystick;
|
bool div_joystick;
|
||||||
bool flip_joystick_bit_1;
|
bool flip_joystick_bit_1;
|
||||||
bool swap_joysticks_bits_1_and_2;
|
bool swap_joysticks_bits_1_and_2;
|
||||||
|
|
||||||
|
char filter[32];
|
||||||
} configuration_t;
|
} configuration_t;
|
||||||
|
|
||||||
extern configuration_t configuration;
|
extern configuration_t configuration;
|
||||||
@ -44,5 +48,6 @@ extern configuration_t configuration;
|
|||||||
void update_viewport(void);
|
void update_viewport(void);
|
||||||
void run_gui(bool is_running);
|
void run_gui(bool is_running);
|
||||||
unsigned fix_joypad_button(unsigned button);
|
unsigned fix_joypad_button(unsigned button);
|
||||||
|
void render_texture(void *pixels, void *previous);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
27
SDL/main.c
27
SDL/main.c
@ -4,6 +4,7 @@
|
|||||||
#include "gb.h"
|
#include "gb.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
|
#include "shader.h"
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#define AUDIO_FREQUENCY 96000
|
#define AUDIO_FREQUENCY 96000
|
||||||
@ -212,10 +213,7 @@ static void handle_events(GB_gameboy_t *gb)
|
|||||||
|
|
||||||
static void vblank(GB_gameboy_t *gb)
|
static void vblank(GB_gameboy_t *gb)
|
||||||
{
|
{
|
||||||
SDL_UpdateTexture(texture, NULL, pixels, 160 * sizeof (uint32_t));
|
render_texture(pixels, NULL);
|
||||||
SDL_RenderClear(renderer);
|
|
||||||
SDL_RenderCopy(renderer, texture, NULL, NULL);
|
|
||||||
SDL_RenderPresent(renderer);
|
|
||||||
handle_events(gb);
|
handle_events(gb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,14 +388,24 @@ usage:
|
|||||||
|
|
||||||
SDL_Init( SDL_INIT_EVERYTHING );
|
SDL_Init( SDL_INIT_EVERYTHING );
|
||||||
|
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||||
|
|
||||||
window = SDL_CreateWindow("SameBoy v" xstr(VERSION), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
window = SDL_CreateWindow("SameBoy v" xstr(VERSION), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
||||||
160 * 2, 144 * 2, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
|
160 * 2, 144 * 2, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
|
||||||
SDL_SetWindowMinimumSize(window, 160, 144);
|
SDL_SetWindowMinimumSize(window, 160, 144);
|
||||||
|
|
||||||
|
SDL_GLContext gl_context = SDL_GL_CreateContext(window);
|
||||||
|
if (gl_context == NULL) {
|
||||||
renderer = SDL_CreateRenderer(window, -1, 0);
|
renderer = SDL_CreateRenderer(window, -1, 0);
|
||||||
|
|
||||||
texture = SDL_CreateTexture(renderer, SDL_GetWindowPixelFormat(window), SDL_TEXTUREACCESS_STREAMING, 160, 144);
|
texture = SDL_CreateTexture(renderer, SDL_GetWindowPixelFormat(window), SDL_TEXTUREACCESS_STREAMING, 160, 144);
|
||||||
|
|
||||||
pixel_format = SDL_AllocFormat(SDL_GetWindowPixelFormat(window));
|
pixel_format = SDL_AllocFormat(SDL_GetWindowPixelFormat(window));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pixel_format = SDL_AllocFormat(SDL_PIXELFORMAT_ABGR8888);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Configure Audio */
|
/* Configure Audio */
|
||||||
memset(&want_aspec, 0, sizeof(want_aspec));
|
memset(&want_aspec, 0, sizeof(want_aspec));
|
||||||
@ -420,6 +428,11 @@ usage:
|
|||||||
|
|
||||||
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
|
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
|
||||||
|
|
||||||
|
if (!init_shader_with_name(&shader, configuration.filter)) {
|
||||||
|
init_shader_with_name(&shader, "NearestNeighbor");
|
||||||
|
}
|
||||||
|
update_viewport();
|
||||||
|
|
||||||
if (filename == NULL) {
|
if (filename == NULL) {
|
||||||
run_gui(false);
|
run_gui(false);
|
||||||
}
|
}
|
||||||
|
184
SDL/shader.c
Normal file
184
SDL/shader.c
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "shader.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include <OpenGL/gl3.h>
|
||||||
|
|
||||||
|
static const char *vertex_shader = "\n\
|
||||||
|
#version 150 \n\
|
||||||
|
in vec4 aPosition;\n\
|
||||||
|
void main(void) {\n\
|
||||||
|
gl_Position = aPosition;\n\
|
||||||
|
}\n\
|
||||||
|
";
|
||||||
|
|
||||||
|
static GLuint create_shader(const char *source, GLenum type)
|
||||||
|
{
|
||||||
|
// Create the shader object
|
||||||
|
GLuint shader = glCreateShader(type);
|
||||||
|
// Load the shader source
|
||||||
|
glShaderSource(shader, 1, &source, 0);
|
||||||
|
// Compile the shader
|
||||||
|
glCompileShader(shader);
|
||||||
|
// Check for errors
|
||||||
|
GLint status = 0;
|
||||||
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
||||||
|
if (status == GL_FALSE) {
|
||||||
|
GLchar messages[1024];
|
||||||
|
glGetShaderInfoLog(shader, sizeof(messages), 0, &messages[0]);
|
||||||
|
fprintf(stderr, "GLSL Shader Error: %s", messages);
|
||||||
|
}
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GLuint create_program(const char *vsh, const char *fsh)
|
||||||
|
{
|
||||||
|
// Build shaders
|
||||||
|
GLuint vertex_shader = create_shader(vsh, GL_VERTEX_SHADER);
|
||||||
|
GLuint fragment_shader = create_shader(fsh, GL_FRAGMENT_SHADER);
|
||||||
|
|
||||||
|
// Create program
|
||||||
|
GLuint program = glCreateProgram();
|
||||||
|
|
||||||
|
// Attach shaders
|
||||||
|
glAttachShader(program, vertex_shader);
|
||||||
|
glAttachShader(program, fragment_shader);
|
||||||
|
|
||||||
|
// Link program
|
||||||
|
glLinkProgram(program);
|
||||||
|
// Check for errors
|
||||||
|
GLint status;
|
||||||
|
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
||||||
|
|
||||||
|
if (status == GL_FALSE) {
|
||||||
|
GLchar messages[1024];
|
||||||
|
glGetProgramInfoLog(program, sizeof(messages), 0, &messages[0]);
|
||||||
|
fprintf(stderr, "GLSL Program Error: %s", messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete shaders
|
||||||
|
glDeleteShader(vertex_shader);
|
||||||
|
glDeleteShader(fragment_shader);
|
||||||
|
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool init_shader_with_name(shader_t *shader, const char *name)
|
||||||
|
{
|
||||||
|
static char master_shader_code[0x801] = {0,};
|
||||||
|
static char shader_code[0x10001] = {0,};
|
||||||
|
static char final_shader_code[0x10801] = {0,};
|
||||||
|
static ssize_t filter_token_location = 0;
|
||||||
|
|
||||||
|
if (!master_shader_code[0]) {
|
||||||
|
FILE *master_shader_f = fopen(executable_relative_path("Shaders/MasterShader.fsh"), "r");
|
||||||
|
if (!master_shader_f) return false;
|
||||||
|
fread(master_shader_code, 1, sizeof(master_shader_code) - 1, master_shader_f);
|
||||||
|
fclose(master_shader_f);
|
||||||
|
filter_token_location = strstr(master_shader_code, "{filter}") - master_shader_code;
|
||||||
|
if (filter_token_location < 0) {
|
||||||
|
master_shader_code[0] = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char shader_path[1024];
|
||||||
|
sprintf(shader_path, "Shaders/%s.fsh", name);
|
||||||
|
|
||||||
|
FILE *shader_f = fopen(executable_relative_path(shader_path), "r");
|
||||||
|
if (!shader_f) return false;
|
||||||
|
memset(shader_code, 0, sizeof(shader_code));
|
||||||
|
fread(shader_code, 1, sizeof(shader_code) - 1, shader_f);
|
||||||
|
fclose(shader_f);
|
||||||
|
|
||||||
|
memset(final_shader_code, 0, sizeof(final_shader_code));
|
||||||
|
memcpy(final_shader_code, master_shader_code, filter_token_location);
|
||||||
|
strcpy(final_shader_code + filter_token_location, shader_code);
|
||||||
|
strcat(final_shader_code + filter_token_location,
|
||||||
|
master_shader_code + filter_token_location + sizeof("{filter}") - 1);
|
||||||
|
|
||||||
|
shader->program = create_program(vertex_shader, final_shader_code);
|
||||||
|
|
||||||
|
// Attributes
|
||||||
|
shader->position_attribute = glGetAttribLocation(shader->program, "aPosition");
|
||||||
|
// Uniforms
|
||||||
|
shader->resolution_uniform = glGetUniformLocation(shader->program, "uResolution");
|
||||||
|
shader->origin_uniform = glGetUniformLocation(shader->program, "uOrigin");
|
||||||
|
|
||||||
|
glGenTextures(1, &shader->texture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, shader->texture);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
shader->texture_uniform = glGetUniformLocation(shader->program, "image");
|
||||||
|
|
||||||
|
glGenTextures(1, &shader->previous_texture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, shader->previous_texture);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
shader->previous_texture_uniform = glGetUniformLocation(shader->program, "previousImage");
|
||||||
|
|
||||||
|
shader->mix_previous_uniform = glGetUniformLocation(shader->program, "uMixPrevious");
|
||||||
|
|
||||||
|
// Program
|
||||||
|
|
||||||
|
glUseProgram(shader->program);
|
||||||
|
|
||||||
|
GLuint vao;
|
||||||
|
glGenVertexArrays(1, &vao);
|
||||||
|
glBindVertexArray(vao);
|
||||||
|
|
||||||
|
GLuint vbo;
|
||||||
|
glGenBuffers(1, &vbo);
|
||||||
|
|
||||||
|
// Attributes
|
||||||
|
|
||||||
|
|
||||||
|
static GLfloat const quad[16] = {
|
||||||
|
-1.f, -1.f, 0, 1,
|
||||||
|
-1.f, +1.f, 0, 1,
|
||||||
|
+1.f, -1.f, 0, 1,
|
||||||
|
+1.f, +1.f, 0, 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW);
|
||||||
|
glEnableVertexAttribArray(shader->position_attribute);
|
||||||
|
glVertexAttribPointer(shader->position_attribute, 4, GL_FLOAT, GL_FALSE, 0, 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_bitmap_with_shader(shader_t *shader, void *bitmap, void *previous,unsigned x, unsigned y, unsigned w, unsigned h)
|
||||||
|
{
|
||||||
|
glUseProgram(shader->program);
|
||||||
|
glUniform2f(shader->origin_uniform, x, y);
|
||||||
|
glUniform2f(shader->resolution_uniform, w, h);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, shader->texture);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 160, 144, 0, GL_RGBA, GL_UNSIGNED_BYTE, bitmap);
|
||||||
|
glUniform1i(shader->texture_uniform, 0);
|
||||||
|
glUniform1i(shader->mix_previous_uniform, previous != NULL);
|
||||||
|
if (previous) {
|
||||||
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, shader->previous_texture);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 160, 144, 0, GL_RGBA, GL_UNSIGNED_BYTE, previous);
|
||||||
|
glUniform1i(shader->previous_texture_uniform, 1);
|
||||||
|
}
|
||||||
|
glBindFragDataLocation(shader->program, 0, "frag_color");
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_shader(shader_t *shader)
|
||||||
|
{
|
||||||
|
glDeleteProgram(shader->program);
|
||||||
|
glDeleteTextures(1, &shader->texture);
|
||||||
|
glDeleteTextures(1, &shader->previous_texture);
|
||||||
|
|
||||||
|
}
|
23
SDL/shader.h
Normal file
23
SDL/shader.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef shader_h
|
||||||
|
#define shader_h
|
||||||
|
#include <OpenGL/gl3.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
typedef struct shader_s {
|
||||||
|
GLuint resolution_uniform;
|
||||||
|
GLuint origin_uniform;
|
||||||
|
GLuint texture_uniform;
|
||||||
|
GLuint previous_texture_uniform;
|
||||||
|
GLuint mix_previous_uniform;
|
||||||
|
|
||||||
|
GLuint position_attribute;
|
||||||
|
GLuint texture;
|
||||||
|
GLuint previous_texture;
|
||||||
|
GLuint program;
|
||||||
|
} shader_t;
|
||||||
|
|
||||||
|
bool init_shader_with_name(shader_t *shader, const char *name);
|
||||||
|
void render_bitmap_with_shader(shader_t *shader, void *bitmap, void *previous,unsigned x, unsigned y, unsigned w, unsigned h);
|
||||||
|
void free_shader(struct shader_s *shader);
|
||||||
|
|
||||||
|
#endif /* shader_h */
|
@ -4,14 +4,20 @@ uniform sampler2D previousImage;
|
|||||||
uniform bool uMixPrevious;
|
uniform bool uMixPrevious;
|
||||||
|
|
||||||
uniform vec2 uResolution;
|
uniform vec2 uResolution;
|
||||||
|
uniform vec2 uOrigin;
|
||||||
const vec2 textureDimensions = vec2(160, 144);
|
const vec2 textureDimensions = vec2(160, 144);
|
||||||
|
|
||||||
out vec4 frag_color;
|
out vec4 frag_color;
|
||||||
|
|
||||||
|
vec4 modified_frag_cord;
|
||||||
|
#define gl_FragCoord modified_frag_cord
|
||||||
#line 1
|
#line 1
|
||||||
{filter}
|
{filter}
|
||||||
|
#undef gl_FragCoord
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
modified_frag_cord = gl_FragCoord - vec4(uOrigin.x, uOrigin.y, 0, 0);
|
||||||
|
|
||||||
if (uMixPrevious) {
|
if (uMixPrevious) {
|
||||||
frag_color = mix(scale(image), scale(previousImage), 0.5);
|
frag_color = mix(scale(image), scale(previousImage), 0.5);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user