diff --git a/Makefile b/Makefile index 35d61d9549..ba2377fab1 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ endif ifeq ($(BUILD_OPENGL), 1) OBJ += gl.o - LIBS += -lglfw + LIBS += -lglfw -lCg -lCgGL endif ifeq ($(BUILD_FILTER), 1) OBJ += hqflt/hq.o diff --git a/config.h b/config.h index 3a6aa8ff13..ac891d0636 100644 --- a/config.h +++ b/config.h @@ -61,7 +61,7 @@ static const unsigned fullscreen_y = 720; static const bool vsync = true; // Smooths picture -static const bool video_smooth = true; +static const bool video_smooth = false; // On resize and fullscreen, rendering area will stay 4:3 static const bool force_aspect = true; @@ -87,7 +87,7 @@ static const bool force_aspect = true; static const bool audio_enable = true; // Output samplerate -static const unsigned out_rate = 48000; +static const unsigned out_rate = 44100; // Input samplerate from libSNES. // Lower this (slightly) if you are experiencing frequent audio dropouts while vsync is enabled. diff --git a/gl.c b/gl.c index 55efa4fbe7..0e6e381c33 100644 --- a/gl.c +++ b/gl.c @@ -24,6 +24,14 @@ #include #include +#include +#include + +// Lots of globals, yes I know. :( +static CGcontext cgCtx; +static CGprogram cgPrg; +static CGprofile cgVProf; + static GLuint texture; static uint8_t *gl_buffer; static bool keep_aspect = true; @@ -37,11 +45,11 @@ static const GLfloat vertexes[] = { 1, 0, 0 }; -static GLfloat tex_coords[] = { - 0, 224.0/512, +static const GLfloat tex_coords[] = { + 0, 1, 0, 0, - 0.5, 0, - 0.5, 224.0/512 + 1, 0, + 1, 1 }; typedef struct gl @@ -217,28 +225,15 @@ static inline void show_fps(void) static bool gl_frame(void *data, const uint16_t* frame, int width, int height, int pitch) { - gl_t *gl = data; + //gl_t *gl = data; + (void)data; glClear(GL_COLOR_BUFFER_BIT); - static int last_width = 256; - static int last_height = 224; - if (width != last_width || height != last_height) - { - tex_coords[0] = 0; - tex_coords[1] = (float)height/gl->real_y; - tex_coords[2] = 0; - tex_coords[3] = 0; - tex_coords[4] = (float)width/gl->real_x; - tex_coords[5] = 0; - tex_coords[6] = (float)width/gl->real_x; - tex_coords[7] = (float)height/gl->real_y; - glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch >> 1); - last_width = width; - last_height = height; - } - - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame); + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch >> 1); + glTexImage2D(GL_TEXTURE_2D, + 0, GL_RGBA, width, height, 0, GL_BGRA, + GL_UNSIGNED_SHORT_1_5_5_5_REV, frame); glDrawArrays(GL_QUADS, 0, 4); show_fps(); @@ -299,16 +294,6 @@ static void* gl_init(video_info_t *video, const input_driver_t **input) glfwSwapInterval(0); gl->vsync = video->vsync; - gl_buffer = calloc(1, 256 * 256 * 2 * video->input_scale * video->input_scale); - if (!gl_buffer) - { - fprintf(stderr, "Couldn't allocate memory :<\n"); - exit(1); - } - - gl->real_x = video->input_scale * 256; - gl->real_y = video->input_scale * 256; - glEnable(GL_TEXTURE_2D); glDisable(GL_DITHER); glDisable(GL_DEPTH_TEST); @@ -323,21 +308,41 @@ static void* gl_init(video_info_t *video, const input_driver_t **input) glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); - glTexImage2D(GL_TEXTURE_2D, - 0, GL_RGB, 256 * video->input_scale, 256 * video->input_scale, 0, GL_BGRA, - GL_UNSIGNED_SHORT_1_5_5_5_REV, gl_buffer); 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, tex_filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, tex_filter); - glPixelStorei(GL_UNPACK_ROW_LENGTH, 1024); 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); + cgCtx = cgCreateContext(); + if (cgCtx == NULL) + { + fprintf(stderr, "Failed to create Cg context\n"); + return NULL; + } + cgVProf = cgGLGetLatestProfile(CG_GL_FRAGMENT); + if (cgVProf == CG_PROFILE_UNKNOWN) + { + fprintf(stderr, "Invalid profile type\n"); + return NULL; + } + cgGLSetOptimalOptions(cgVProf); + cgPrg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, "hqflt/crt.cg", cgVProf, "main", 0); + if (cgPrg == NULL) + { + CGerror err = cgGetError(); + fprintf(stderr, "CG error: %s\n", cgGetErrorString(err)); + return NULL; + } + cgGLLoadProgram(cgPrg); + cgGLEnableProfile(cgVProf); + cgGLBindProgram(cgPrg); + *input = &input_glfw; return gl; } diff --git a/hqflt/crt.cg b/hqflt/crt.cg new file mode 100644 index 0000000000..77e703c752 --- /dev/null +++ b/hqflt/crt.cg @@ -0,0 +1,79 @@ + +#define TEX2D(c) tex2D(decal,(c)) +#define PI 3.141592653589 +#define phase 0.0 +#define gamma 2.5 + +#define distortion 0.2 + +struct output +{ + float4 color : COLOR; +}; + + +//uniform float2 rubyInputSize; +//uniform float2 rubyOutputSize; +//uniform float2 rubyTextureSize; + +float2 fract(float2 v) +{ + float2 ret; + + ret.x = v.x - floor(v.x); + ret.y = v.y - floor(v.y); + + return ret; +} + +float2 barrelDistortion(float2 coord) { + float2 cc = coord - 0.5; + float dist = dot(cc, cc); + return coord + cc * (dist + distortion * dist * dist) * distortion; +} + +output main(float2 texCoord : TEXCOORD0, uniform sampler2D decal : TEXUNIT0) +{ + output OUT; + + float2 rubyInputSize = float2(256, 224); + float2 rubyOutputSize = float2(256, 224); + float2 rubyTextureSize = float2(256, 224); + + float2 xy = barrelDistortion(texCoord.xy); + float2 one = 1.0/rubyTextureSize; + xy = xy + float2(0.0 , -0.5 * (phase + (1-phase) * rubyInputSize.y/rubyOutputSize.y) * one.y); + + //float2 uv_ratio = fract(xy*rubyTextureSize); + float2 uv_ratio = frac(xy*rubyTextureSize); + + float4 col, col2; + + float4 coeffs = float4(1.0 + uv_ratio.x, uv_ratio.x, 1.0 - uv_ratio.x, 2.0 - uv_ratio.x); + coeffs = (sin(PI * coeffs) * sin(PI * coeffs / 2.0)) / (coeffs * coeffs); + coeffs = coeffs / (coeffs.x+coeffs.y+coeffs.z+coeffs.w); + + col = clamp(coeffs.x * TEX2D(xy + float2(-one.x,0.0)) + coeffs.y * TEX2D(xy) + coeffs.z * TEX2D(xy + float2(one.x, 0.0)) + coeffs.w * TEX2D(xy + float2(2 * one.x, 0.0)),0.0,1.0); + col2 = clamp(coeffs.x * TEX2D(xy + float2(-one.x,one.y)) + coeffs.y * TEX2D(xy + float2(0.0, one.y)) + coeffs.z * TEX2D(xy + one) + coeffs.w * TEX2D(xy + float2(2 * one.x, one.y)),0.0,1.0); + col = pow(col, gamma); + col2 = pow(col2, gamma); + + float4 wid = 2 + 2 * pow(col, 4.0); + float4 weights = uv_ratio.y/0.3; + weights = 0.51*exp(-pow(weights*sqrt(2/wid),wid))/0.3/(0.6+0.2*wid); + wid = 2 + 4 * pow(col2,4.0); + float4 weights2 = (1.0-uv_ratio.y)/0.3; + weights2 = 0.51*exp(-pow(weights2*sqrt(2/wid),wid))/0.3/(0.6+0.2*wid); + + float4 mcol = 1.0; + if ( fmod(xy.x*rubyOutputSize.x,2.0) < 1.0) + mcol.g = 0.7; + else + mcol.rb = 0.7; + + OUT.color = pow(mcol*(col * weights + col2 * weights2), 1.0/2.2); + + return OUT; +} + +