Start on modular CPU filters. Abandon the old CPU filter stuff.

This commit is contained in:
Themaister 2011-03-07 17:22:03 +01:00
parent ec367d333d
commit 96b978d55a
29 changed files with 17 additions and 2559 deletions

View File

@ -243,6 +243,7 @@ void init_video_input(void)
.force_aspect = g_settings.video.force_aspect,
.smooth = g_settings.video.smooth,
.input_scale = scale,
.rgb32 = g_extern.filter.active
};
const input_driver_t *tmp = driver.input;

View File

@ -59,6 +59,7 @@ typedef struct video_info
bool force_aspect;
bool smooth;
int input_scale; // HQ2X => 2, HQ4X => 4, None => 1
bool rgb32; // Use 32-bit RGBA rather than native XBGR1555.
} video_info_t;
typedef struct audio_driver
@ -106,7 +107,7 @@ typedef struct video_driver
{
void* (*init)(video_info_t *video, const input_driver_t **input, void **input_data);
// Should the video driver act as an input driver as well? :) The video init might preinitialize an input driver to override the settings in case the video driver relies on input driver for event handling, e.g.
bool (*frame)(void* data, const uint16_t* frame, unsigned width, unsigned height, unsigned pitch, const char *msg); // msg is for showing a message on the screen along with the video frame.
bool (*frame)(void* data, const void* frame, unsigned width, unsigned height, unsigned pitch, const char *msg); // msg is for showing a message on the screen along with the video frame.
void (*set_nonblock_state)(void* data, bool toggle); // Should we care about syncing to vblank? Fast forwarding.
// Is the window still active?
bool (*alive)(void *data);

View File

@ -69,7 +69,7 @@ struct settings
float aspect_ratio;
char cg_shader_path[256];
char bsnes_shader_path[256];
unsigned filter;
char filter_path[256];
enum ssnes_shader_type shader_type;
bool render_to_texture;

View File

@ -1,45 +0,0 @@
#include "bleed.h"
#include <stdlib.h>
#include <string.h>
void bleed_filter(uint16_t *data, int width, int height)
{
uint16_t tmp[4];
int ptr = 0;
uint16_t r[4];
uint16_t g[4];
uint16_t b[4];
uint16_t bleed_r;
uint16_t bleed_g;
uint16_t bleed_b;
float rand_map[4];
for (int h = 0; h < height; h++ )
{
memcpy(tmp, data, sizeof(tmp));
ptr = 3;
for (int i = 0; i < 4; i++)
{
rand_map[i] = (rand() % 20)/1000.0; // 0.02 * 4 = 0.08
}
for (int i = 3; i < width; i++, ptr++)
{
tmp[ptr & 0x3] = data[i];
for (int y = 0; y < 4; y++)
{
r[y] = (tmp[(ptr + y) & 0x3] >> 10) & 0x1F;
g[y] = (tmp[(ptr + y) & 0x3] >> 5) & 0x1F;
b[y] = (tmp[(ptr + y) & 0x3] >> 0) & 0x1F;
}
bleed_r = r[0] * (0.05 + rand_map[0] ) + r[1] * (0.10 + rand_map[1] ) + r[2] * (0.20 + rand_map[2]) + r[3] * (0.57 + rand_map[3] ); // 0.92
bleed_g = g[0] * (0.03 + rand_map[2]/3) + g[1] * (0.10 + rand_map[0]/3) + g[2] * (0.20 + rand_map[3]/3) + g[3] * (0.63 + rand_map[1]/3); // 0.96
bleed_b = b[0] * (0.05 + rand_map[3] ) + b[1] * (0.10 + rand_map[2] ) + b[2] * (0.20 + rand_map[1]) + b[3] * (0.57 + rand_map[0] ); // 0.92
data[i] = (bleed_r << 10) | (bleed_g << 5) | (bleed_b);
}
data += width;
}
}

View File

@ -1,3 +0,0 @@
#include <stdint.h>
void bleed_filter(uint16_t *data, int width, int height);

View File

@ -1,94 +0,0 @@
/*
Copyright (C) 2007 guest(r) - guest.r@gmail.com
This program 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 Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
The 2xSaL shader processes a gfx. surface and redraws it 2x finer.
A linear post-resize can fit the image to any resolution.
Note: set scaler to normal2x.
*/
/* Default Vertex shader */
void main_vertex
(
float4 position : POSITION,
float4 color : COLOR,
float2 texCoord : TEXCOORD0,
uniform float4x4 modelViewProj,
out float4 oPosition : POSITION,
out float4 oColor : COLOR,
out float2 otexCoord : TEXCOORD
)
{
oPosition = mul(modelViewProj, position);
oColor = color;
otexCoord = texCoord;
}
struct output
{
float4 color : COLOR;
};
struct input
{
float2 video_size;
float2 texture_size;
float2 output_size;
};
struct deltas
{
float2 UL, UR, DL, DR;
};
output main_fragment (float2 tex : TEXCOORD0, uniform input IN, uniform sampler2D s_p : TEXUNIT0)
{
float2 texsize = IN.texture_size;
float dx = pow(texsize.x, -1.0) * 0.25;
float dy = pow(texsize.y, -1.0) * 0.25;
float3 dt = float3(1.0, 1.0, 1.0);
deltas VAR = {
tex + float2(-dx, -dy),
tex + float2(dx, -dy),
tex + float2(-dx, dy),
tex + float2(dx, dy)
};
float3 c00 = tex2D(s_p, VAR.UL).xyz;
float3 c20 = tex2D(s_p, VAR.UR).xyz;
float3 c02 = tex2D(s_p, VAR.DL).xyz;
float3 c22 = tex2D(s_p, VAR.DR).xyz;
float m1=dot(abs(c00-c22),dt)+0.001;
float m2=dot(abs(c02-c20),dt)+0.001;
output OUT;
OUT.color = float4((m1*(c02+c20)+m2*(c22+c00))/(2.0*(m1+m2)),1.0);
return OUT;
}

View File

@ -1,95 +0,0 @@
/* Default Vertex shader */
void main_vertex
(
float4 position : POSITION,
float4 color : COLOR,
float2 texCoord : TEXCOORD0,
uniform float4x4 modelViewProj,
out float4 oPosition : POSITION,
out float4 oColor : COLOR,
out float2 otexCoord : TEXCOORD
)
{
oPosition = mul(modelViewProj, position);
oColor = color;
otexCoord = texCoord;
}
float Luminance = 0.09f;
static const float fMiddleGray = 0.18f;
static const float fWhiteCutoff = 0.8f;
#define NUM 13
float2 PixelOffsets[NUM] =
{
{ -0.006, -0.006 },
{ -0.005, -0.005 },
{ -0.004, -0.004 },
{ -0.003, -0.003 },
{ -0.002, -0.002 },
{ -0.001, -0.001 },
{ 0.000, 0.000 },
{ 0.001, 0.001 },
{ 0.002, 0.002 },
{ 0.003, 0.003 },
{ 0.004, 0.004 },
{ 0.005, 0.005 },
{ 0.006, 0.006 },
};
static const float BlurWeights[NUM] =
{
0.002216,
0.008764,
0.026995,
0.064759,
0.120985,
0.176033,
0.199471,
0.176033,
0.120985,
0.064759,
0.026995,
0.008764,
0.002216,
};
struct output
{
float4 color : COLOR;
};
output main_fragment( float2 Tex : TEXCOORD0, uniform sampler2D s0 : TEXUNIT0 )
{
float2 BloomSettings;
BloomSettings.x = 1;
BloomSettings.y = 0.3;
float3 pixel;
float3 Color = 0;
for(int i = 0; i < NUM; i++)
{
pixel = tex2D(s0, Tex + PixelOffsets[i] * 5.0f)+BloomSettings.y;
pixel *= fMiddleGray / (Luminance + 0.001f);
pixel *= (1.0f + (pixel / (fWhiteCutoff * fWhiteCutoff)));
pixel -= 5.0f;
pixel = max(pixel,0.0f);
pixel /= (10.0f + pixel);
Color += pixel * BlurWeights[i];
}
Color *= BloomSettings.x;
output OUT;
OUT.color = float4(Color,1.0) + tex2D(s0,Tex);
return OUT;
}

View File

@ -1,55 +0,0 @@
/* Default Vertex shader */
void main_vertex
(
float4 position : POSITION,
float4 color : COLOR,
float2 texCoord : TEXCOORD0,
uniform float4x4 modelViewProj,
out float4 oPosition : POSITION,
out float4 oColor : COLOR,
out float2 otexCoord : TEXCOORD
)
{
oPosition = mul(modelViewProj, position);
oColor = color;
otexCoord = texCoord;
}
const float2 samples[12]
= {
-0.326212, -0.405805,
-0.840144, -0.073580,
-0.695914, 0.457137,
-0.203345, 0.620716,
0.962340, -0.194983,
0.473434, -0.480026,
0.519456, 0.767022,
0.185461, -0.893124,
0.507431, 0.064425,
0.896420, 0.412458,
-0.321940, -0.932615,
-0.791559, -0.597705
};
struct output
{
float4 col : COLOR;
};
output main_fragment(in float2 Tex : TEXCOORD0, uniform sampler2D s0 : TEXUNIT0 )
{
float4 color = tex2D( s0, Tex.xy);
float BlurFactor = 0.0025; //set between 0.001 and 0.05
for (int i = 0; i < 12; i++)
{
color += tex2D(s0, Tex + BlurFactor * samples[i]);
}
output OUT;
OUT.col = color / 13;
return OUT;
}

View File

@ -1,100 +0,0 @@
/* Default Vertex shader */
void main_vertex
(
float4 position : POSITION,
float4 color : COLOR,
float2 texCoord : TEXCOORD0,
uniform float4x4 modelViewProj,
out float4 oPosition : POSITION,
out float4 oColor : COLOR,
out float2 otexCoord : TEXCOORD
)
{
oPosition = mul(modelViewProj, position);
oColor = color;
otexCoord = texCoord;
}
#define TEX2D(c) tex2D(decal,(c))
#define PI 3.141592653589
#define phase 0.0
#define gamma 2.5
#define distortion 0.04
struct output
{
float4 color : COLOR;
};
struct input
{
float2 video_size;
float2 texture_size;
float2 output_size;
};
float2 barrelDistortion(float2 coord)
{
float2 cc = coord - 0.5;
float dist = dot(cc, cc);
return coord + cc * (dist + distortion * dist * dist) * distortion;
}
output main_fragment(float2 texCoord : TEXCOORD0, uniform sampler2D decal : TEXUNIT0, uniform input IN)
{
output OUT;
float2 rubyInputSize = IN.video_size;
float2 rubyOutputSize = IN.output_size;
float2 rubyTextureSize = IN.texture_size;
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);
float4 texels[8];
texels[0] = TEX2D(xy + float2(-one.x,0.0));
texels[1] = TEX2D(xy);
texels[2] = TEX2D(xy + float2(one.x, 0.0));
texels[3] = TEX2D(xy + float2(2 * one.x, 0.0));
texels[4] = TEX2D(xy + float2(-one.x,one.y));
texels[5] = TEX2D(xy + float2(0.0, one.y));
texels[6] = TEX2D(xy + one);
texels[7] = TEX2D(xy + float2(2 * one.x, one.y));
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 * texels[0] + coeffs.y * texels[1] + coeffs.z * texels[2] + coeffs.w * texels[3], 0.0, 1.0);
col2 = clamp(coeffs.x * texels[4] + coeffs.y * texels[5] + coeffs.z * texels[6] + coeffs.w * texels[7], 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);
//OUT.color = 1.0;
return OUT;
}

View File

@ -1,94 +0,0 @@
/* Default Vertex shader */
void main_vertex
(
float4 position : POSITION,
float4 color : COLOR,
float2 texCoord : TEXCOORD0,
uniform float4x4 modelViewProj,
out float4 oPosition : POSITION,
out float4 oColor : COLOR,
out float2 otexCoord : TEXCOORD
)
{
oPosition = mul(modelViewProj, position);
oColor = color;
otexCoord = texCoord;
}
struct output
{
float4 color : COLOR;
};
struct input
{
float2 video_size;
float2 texture_size;
float2 output_size;
};
const float mx = 0.325; // start smoothing wt.
const float k = -0.250; // wt. decrease factor
const float max_w = 0.25; // max filter weigth
const float min_w =-0.05; // min filter weigth
const float lum_add = 0.25; // effects smoothing
output main_fragment(float2 texCoord : TEXCOORD0, uniform sampler2D decal : TEXUNIT0, uniform input IN)
{
float x = 0.5 * (1.0 / IN.texture_size.x);
float y = 0.5 * (1.0 / IN.texture_size.y);
float2 dg1 = float2( x, y);
float2 dg2 = float2(-x, y);
float2 dx = float2(x, 0.0);
float2 dy = float2(0.0, y);
float4 TexCoord[5];
TexCoord[0] = float4(texCoord, 0.0, 0.0);
TexCoord[1].xy = TexCoord[0].xy - dg1;
TexCoord[1].zw = TexCoord[0].xy - dy;
TexCoord[2].xy = TexCoord[0].xy - dg2;
TexCoord[2].zw = TexCoord[0].xy + dx;
TexCoord[3].xy = TexCoord[0].xy + dg1;
TexCoord[3].zw = TexCoord[0].xy + dy;
TexCoord[4].xy = TexCoord[0].xy + dg2;
TexCoord[4].zw = TexCoord[0].xy - dx;
float3 c00 = tex2D(decal, TexCoord[1].xy).xyz;
float3 c10 = tex2D(decal, TexCoord[1].zw).xyz;
float3 c20 = tex2D(decal, TexCoord[2].xy).xyz;
float3 c01 = tex2D(decal, TexCoord[4].zw).xyz;
float3 c11 = tex2D(decal, TexCoord[0].xy).xyz;
float3 c21 = tex2D(decal, TexCoord[2].zw).xyz;
float3 c02 = tex2D(decal, TexCoord[4].xy).xyz;
float3 c12 = tex2D(decal, TexCoord[3].zw).xyz;
float3 c22 = tex2D(decal, TexCoord[3].xy).xyz;
float3 dt = float3(1.0, 1.0, 1.0);
float md1 = dot(abs(c00 - c22), dt);
float md2 = dot(abs(c02 - c20), dt);
float w1 = dot(abs(c22 - c11), dt) * md2;
float w2 = dot(abs(c02 - c11), dt) * md1;
float w3 = dot(abs(c00 - c11), dt) * md2;
float w4 = dot(abs(c20 - c11), dt) * md1;
float t1 = w1 + w3;
float t2 = w2 + w4;
float ww = max(t1, t2) + 0.0001;
c11 = (w1 * c00 + w2 * c20 + w3 * c22 + w4 * c02 + ww * c11) / (t1 + t2 + ww);
float lc1 = k / (0.12 * dot(c10 + c12 + c11, dt) + lum_add);
float lc2 = k / (0.12 * dot(c01 + c21 + c11, dt) + lum_add);
w1 = clamp(lc1 * dot(abs(c11 - c10), dt) + mx, min_w, max_w);
w2 = clamp(lc2 * dot(abs(c11 - c21), dt) + mx, min_w, max_w);
w3 = clamp(lc1 * dot(abs(c11 - c12), dt) + mx, min_w, max_w);
w4 = clamp(lc2 * dot(abs(c11 - c01), dt) + mx, min_w, max_w);
output OUT;
OUT.color = float4(w1 * c10 + w2 * c21 + w3 * c12 + w4 * c01 + (1.0 - w1 - w2 - w3 - w4) * c11, 1.0);
return OUT;
}

View File

@ -1,87 +0,0 @@
/*
Author: Themaister
License: Public domain
*/
/* Default Vertex shader */
void main_vertex
(
float4 position : POSITION,
float4 color : COLOR,
float2 texCoord : TEXCOORD0,
uniform float4x4 modelViewProj,
out float4 oPosition : POSITION,
out float4 oColor : COLOR,
out float2 otexCoord : TEXCOORD
)
{
oPosition = mul(modelViewProj, position);
oColor = color;
otexCoord = texCoord;
}
struct output
{
float4 color : COLOR;
};
struct input
{
float2 video_size;
float2 texture_size;
float2 output_size;
};
struct deltas
{
float2 UL, UR, DL, DR;
};
float3 quad_inter(float3 x0, float3 x1, float3 x2, float x)
{
float3 poly[3];
poly[2] = 0.5*x0 - x1 + 0.5*x2;
poly[1] = -1.5*x0 + 2.0*x1 - 0.5*x2;
poly[0] = x0;
return poly[2] * x * x + poly[1] * x + poly[0];
}
output main_fragment (float2 tex : TEXCOORD0, uniform input IN, uniform sampler2D s0 : TEXUNIT0)
{
float2 texsize = IN.texture_size;
float sharpness = 2.0;
float dx = float(pow(sharpness * texsize.x, -1.0));
float dy = float(pow(sharpness * texsize.y, -1.0));
float3 c00 = tex2D(s0, tex + float2(-dx, -dy)).xyz;
float3 c01 = tex2D(s0, tex + float2(-dx, 0)).xyz;
float3 c02 = tex2D(s0, tex + float2(-dx, dy)).xyz;
float3 c10 = tex2D(s0, tex + float2(0, -dy)).xyz;
float3 c11 = tex2D(s0, tex + float2(0, 0)).xyz;
float3 c12 = tex2D(s0, tex + float2(0, dy)).xyz;
float3 c20 = tex2D(s0, tex + float2(dx, -dy)).xyz;
float3 c21 = tex2D(s0, tex + float2(dx, 0)).xyz;
float3 c22 = tex2D(s0, tex + float2(dx, dy)).xyz;
float frac_amt_x = frac(tex.x * texsize.x);
float frac_amt_y = frac(tex.y * texsize.y);
float3 loval = quad_inter(c00, c10, c20, frac_amt_x + 0.5);
float3 midval = quad_inter(c01, c11, c21, frac_amt_x + 0.5);
float3 hival = quad_inter(c02, c12, c22, frac_amt_x + 0.5);
float3 res = quad_inter(loval, midval, hival, frac_amt_y + 0.5);
output OUT;
// Bilinear!
// float3 first = lerp(c00, c20, frac(tex.x * texsize.x + 0.5));
// float3 second = lerp(c02, c22, frac(tex.x * texsize.x + 0.5));
// float3 res = lerp(first, second, frac(tex.y * texsize.y + 0.5));
// OUT.color = float4(res, 1.0);
OUT.color = float4(res, 1.0);
return OUT;
}

View File

@ -1,46 +0,0 @@
/* Default Vertex shader */
void main_vertex
(
float4 position : POSITION,
float4 color : COLOR,
float2 texCoord : TEXCOORD0,
uniform float4x4 modelViewProj,
out float4 oPosition : POSITION,
out float4 oColor : COLOR,
out float2 otexCoord : TEXCOORD
)
{
oPosition = mul(modelViewProj, position);
oColor = color;
otexCoord = texCoord;
}
struct output
{
float4 color : COLOR;
};
struct input
{
float2 video_size;
float2 texture_size;
float2 output_size;
};
output main_fragment(float2 texCoord : TEXCOORD0, uniform sampler2D decal : TEXUNIT0, uniform input IN)
{
output OUT;
float winHeight = IN.output_size.y;
float4 tex_color = tex2D(decal, texCoord);
OUT.color = (1.0 - 0.60 * floor(fmod(texCoord.y * winHeight, 2.0))) * tex_color;
return OUT;
}

View File

@ -1,38 +0,0 @@
/* Default Vertex shader */
void main_vertex
(
float4 position : POSITION,
float4 color : COLOR,
float2 texCoord : TEXCOORD0,
uniform float4x4 modelViewProj,
out float4 oPosition : POSITION,
out float4 oColor : COLOR,
out float2 otexCoord : TEXCOORD
)
{
oPosition = mul(modelViewProj, position);
oColor = color;
otexCoord = texCoord;
}
struct output
{
float4 color : COLOR;
};
output main_fragment( in float2 Tex : TEXCOORD0, uniform sampler2D s0 : TEXUNIT0 )
{
float4 Color = tex2D( s0, Tex.xy );
float Sharpenfactor = 30; //Make this between 10 and 50;
Color -= tex2D( s0, Tex.xy+0.0001)*Sharpenfactor;
Color += tex2D( s0, Tex.xy-0.0001)*Sharpenfactor;
Color.a = 1.0;
output OUT;
OUT.color = Color;
return OUT;
}

View File

@ -1,71 +0,0 @@
/*
Author: Themaister
License: Public domain
*/
/* Default Vertex shader */
void main_vertex
(
float4 position : POSITION,
float4 color : COLOR,
float2 texCoord : TEXCOORD0,
uniform float4x4 modelViewProj,
out float4 oPosition : POSITION,
out float4 oColor : COLOR,
out float2 otexCoord : TEXCOORD
)
{
oPosition = mul(modelViewProj, position);
oColor = color;
otexCoord = texCoord;
}
struct output
{
float4 color : COLOR;
};
struct input
{
float2 video_size;
float2 texture_size;
float2 output_size;
};
output main_fragment (float2 tex : TEXCOORD0, uniform input IN, uniform sampler2D s0 : TEXUNIT0)
{
float2 texsize = IN.texture_size;
const float scale_factor = 1.0;
float2 delta = 0.5 / (texsize * scale_factor);
float dx = delta.x;
float dy = delta.y;
float3 c00 = tex2D(s0, tex + float2(-dx, -dy)).xyz;
float3 c01 = tex2D(s0, tex + float2(-dx, 0)).xyz;
float3 c02 = tex2D(s0, tex + float2(-dx, dy)).xyz;
float3 c10 = tex2D(s0, tex + float2(0, -dy)).xyz;
float3 c11 = tex2D(s0, tex + float2(0, 0)).xyz;
float3 c12 = tex2D(s0, tex + float2(0, dy)).xyz;
float3 c20 = tex2D(s0, tex + float2(dx, -dy)).xyz;
float3 c21 = tex2D(s0, tex + float2(dx, 0)).xyz;
float3 c22 = tex2D(s0, tex + float2(dx, dy)).xyz;
output OUT;
float3 first = lerp(c00, c20, frac(scale_factor * tex.x * texsize.x + 0.5));
float3 second = lerp(c02, c22, frac(scale_factor * tex.x * texsize.x + 0.5));
float3 mid_horiz = lerp(c01, c21, frac(scale_factor * tex.x * texsize.x + 0.5));
float3 mid_vert = lerp(c10, c12, frac(scale_factor * tex.y * texsize.y + 0.5));
float3 res = lerp(first, second, frac(scale_factor * tex.y * texsize.y + 0.5));
OUT.color = float4(0.28 * (res + mid_horiz + mid_vert) + 4.7 * abs(res - lerp(mid_horiz, mid_vert, 0.5)), 1.0);
return OUT;
}

View File

@ -1,76 +0,0 @@
/*
Author: Themaister
License: Public domain
*/
/* Default Vertex shader */
void main_vertex
(
float4 position : POSITION,
float4 color : COLOR,
float2 texCoord : TEXCOORD0,
uniform float4x4 modelViewProj,
out float4 oPosition : POSITION,
out float4 oColor : COLOR,
out float2 otexCoord : TEXCOORD
)
{
oPosition = mul(modelViewProj, position);
oColor = color;
otexCoord = texCoord;
}
struct output
{
float4 color : COLOR;
};
struct input
{
float2 video_size;
float2 texture_size;
float2 output_size;
};
float4 compress(float4 in_color, float threshold, float ratio)
{
float4 diff = in_color - float4(threshold);
diff = clamp(diff, 0.0, 100.0);
return in_color - (diff * (1.0 - 1.0/ratio));
}
output main_fragment (float2 tex : TEXCOORD0, uniform input IN, uniform sampler2D s0 : TEXUNIT0)
{
float2 texsize = IN.texture_size;
const float scale_factor = 1.0;
float2 delta = 0.5 / (texsize * scale_factor);
float dx = delta.x;
float dy = delta.y;
float3 c00 = tex2D(s0, tex + float2(-dx, -dy)).xyz;
float3 c01 = tex2D(s0, tex + float2(-dx, 0)).xyz;
float3 c02 = tex2D(s0, tex + float2(-dx, dy)).xyz;
float3 c10 = tex2D(s0, tex + float2(0, -dy)).xyz;
float3 c11 = tex2D(s0, tex + float2(0, 0)).xyz;
float3 c12 = tex2D(s0, tex + float2(0, dy)).xyz;
float3 c20 = tex2D(s0, tex + float2(dx, -dy)).xyz;
float3 c21 = tex2D(s0, tex + float2(dx, 0)).xyz;
float3 c22 = tex2D(s0, tex + float2(dx, dy)).xyz;
output OUT;
float3 first = lerp(c00, c20, frac(scale_factor * tex.x * texsize.x + 0.5));
float3 second = lerp(c02, c22, frac(scale_factor * tex.x * texsize.x + 0.5));
float3 mid_horiz = lerp(c01, c21, frac(scale_factor * tex.x * texsize.x + 0.5));
float3 mid_vert = lerp(c10, c12, frac(scale_factor * tex.y * texsize.y + 0.5));
float3 res = lerp(first, second, frac(scale_factor * tex.y * texsize.y + 0.5));
float4 final = float4(0.26 * (res + mid_horiz + mid_vert) + 3.5 * abs(res - lerp(mid_horiz, mid_vert, 0.5)), 1.0);
OUT.color = compress(final, 0.8, 5.0);
return OUT;
}

View File

@ -1,46 +0,0 @@
/* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef __FILTERS_H
#define __FILTERS_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_FILTER
#include "pastlib.h"
#include "grayscale.h"
#include "bleed.h"
#include "ntsc.h"
#define FILTER_NONE 0
#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

View File

@ -1,21 +0,0 @@
/* Very simple grayscale filter.
* Author: Hans-Kristian Arntzen
* License: Public domain
*/
#include "grayscale.h"
// Input format 0RRRRRGGGGGBBBBB. Colors themselves could be switched around.
void grayscale_filter(uint16_t *data, int width, int height)
{
for (int i = 0; i < width * height; i++ )
{
int r, g, b, color;
r = (data[i] >> 10) & 0x1F;
g = (data[i] >> 5) & 0x1F;
b = (data[i] >> 0) & 0x1F;
color = (int)(r * 0.3 + g * 0.59 + b * 0.11);
data[i] = (color << 10) | (color << 5) | color;
}
}

View File

@ -1,7 +0,0 @@
/* Very simple grayscale filter.
* Author: Hans-Kristian Arntzen
* License: Public domain
*/
#include <stdint.h>
void grayscale_filter(uint16_t *data, int width, int height);

View File

@ -1,555 +0,0 @@
/* This source code is Copyright (C) 2006-2009 by WolfWings. */
/* It is, however, released under the ISC license. */
/* en.wikipedia.org/wiki/ISC_Licence */
/* --------------------------------------------------------- */
/* It is a formula-level rederiviation of the HQ2x technique */
/* and is, thus, not a derivative work of the original code, */
/* only the original equations behind the code. */
#include <stdlib.h>
#include <string.h>
#include "pastlib.h"
static const uint8_t blends_2x[14*4] = {
/* 5 2 4 1 */
8, 4, 4, 0,
8, 4, 0, 4,
8, 0, 4, 4,
16, 0, 0, 0,
12, 4, 0, 0,
12, 0, 4, 0,
12, 0, 0, 4,
4, 6, 6, 0, /* Interp9 */
12, 2, 2, 0, /* Interp7 */
14, 1, 1, 0, /* Interp10*/
10, 4, 2, 0, /* Interp6 */
10, 2, 4, 0, /* Interp6 */
4, 6, 6, 0, /* Added for secondary blending used in HQ4x */
8, 4, 4, 0, /* Added for secondary blending used in HQ4x */
};
static const uint8_t blends_4x[14*16] = {
/* 5 2 4 1 5 2 4 1 5 2 4 1 5 2 4 1 */
8, 4, 4, 0, 10, 4, 2, 0, 10, 2, 4, 0, 12, 2, 2, 0, /* Needs to be split. B */
10, 0, 0, 6, 10, 4, 0, 2, 12, 0, 0, 4, 14, 0, 0, 2,
10, 0, 0, 6, 10, 0, 4, 2, 12, 0, 0, 4, 14, 0, 0, 2,
16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, /* Solid colors */
10, 6, 0, 0, 10, 6, 0, 0, 14, 2, 0, 0, 14, 2, 0, 0,
10, 0, 6, 0, 14, 0, 2, 0, 10, 0, 6, 0, 14, 0, 2, 0,
10, 0, 0, 6, 12, 0, 0, 4, 12, 0, 0, 4, 14, 0, 0, 2,
0, 8, 8, 0, 4, 8, 4, 0, 0, 6,10, 0, 12, 2, 2, 0, /* Needs to be split. A */
8, 4, 4, 0, 12, 4, 0, 0, 12, 0, 4, 0, 16, 0, 0, 0,
8, 4, 4, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0,
12, 4, 0, 0, 4,12, 0, 0, 10, 0, 4, 0, 14, 0, 2, 0,
12, 0, 4, 0, 10, 4, 0, 0, 4, 0,12, 0, 14, 2, 0, 0,
0, 8, 8, 0, 0,10, 6, 0, 4, 4, 8, 0, 12, 2, 2, 0, /* Needs to be split. A */
0, 8, 8, 0, 8, 8, 0, 0, 8, 0, 8, 0, 16, 0, 0, 0, /* Needs to be split. B */
};
static const uint8_t tree_hq[0x800] = {
/* 6 6 6 6 6 6 6 6
* 2 2 2 2 2 2 2 2
* 4 4 4 4 4 4 4 4
* 8 8 8 8 8 8 8 8
*/
0, 0, 2, 2, 1, 1,13,13, 0, 0, 2, 2, 1, 1,13, 8, /* */
0, 0, 2, 2, 1, 1,12, 6, 0, 0, 2, 2, 1, 1, 8, 8, /* 3 */
0, 0, 5,10, 4, 4,13,13, 0, 0, 5, 5,11, 4,13,13, /* 1 */
0, 0, 5,10, 4, 4,12,13, 0, 0, 5, 5,11, 4,13,13, /* 31 */
0, 0, 2, 2, 1, 1, 7, 8, 0, 0, 2, 2, 1, 1, 6, 8, /* 7 */
0, 0, 2, 2, 1, 1, 8, 6, 0, 0, 2, 2, 1, 1, 6, 6, /* 3 7 */
0, 0, 5,10, 4, 4, 7,13, 0, 0, 5, 5,11, 4,13,13, /* 17 */
0, 0, 5,10, 4, 4, 9, 9, 0, 0, 5,10,11,11, 9, 9, /* 317 */
0, 0, 2, 2, 1, 1,13, 8, 0, 0, 2, 2, 1, 1, 8, 8, /* 9 */
0, 0, 2, 2, 1, 1,12, 8, 0, 0, 2, 2, 1, 1, 8, 6, /* 3 9 */
0, 0, 5, 5, 4, 4,13,13, 0, 0, 5, 5, 4, 4,13,13, /* 1 9 */
0, 0, 5, 5, 4, 4,12,13, 0, 0, 5, 5, 4, 4,12,13, /* 31 9 */
0, 0, 2, 2, 1, 1, 7, 8, 0, 0, 2, 2, 1, 1, 8, 6, /* 79 */
0, 0, 2, 2, 1, 1, 8, 6, 0, 0, 2, 2, 1, 1, 6, 6, /* 3 79 */
0, 0, 5, 5, 4, 4, 7, 7, 0, 0, 5, 5, 4, 4,13,13, /* 179 */
0, 0, 5, 5, 4, 4, 9, 9, 0, 0, 5, 5, 4, 4, 9, 9, /* 3179 */
/* DIFF26 */
0, 0, 2, 2, 1, 1,13,13, 0, 0, 2, 2, 1, 1,13, 8,
0, 0, 2, 2, 1, 1,12, 6, 0, 0, 2, 2, 1, 1, 8, 8,
0, 0, 5, 5, 4, 4,13,13, 0, 0, 5, 5,11, 4,13,13,
0, 0, 5, 5, 4, 4,12,13, 0, 0, 5, 5,11, 4,13,13,
0, 0, 2, 2, 1, 1, 7, 8, 0, 0, 2, 2, 1, 1, 6, 8,
0, 0, 2, 2, 1, 1, 8, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 7,13, 0, 0, 5, 5,11, 4,13,13,
0, 0, 5, 5, 4, 4, 9, 9, 0, 0, 5, 5,11,11, 9, 9,
0, 0, 2, 2, 1, 1,13, 8, 0, 0, 2, 2, 1, 1, 8, 8,
0, 0, 2, 2, 1, 1,12, 8, 0, 0, 2, 2, 1, 1, 8, 6,
0, 0, 5, 5, 4, 4,13,13, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 5, 5, 4, 4,12,13, 0, 0, 5, 5, 4, 4,12,13,
0, 0, 2, 2, 1, 1, 7, 8, 0, 0, 2, 2, 1, 1, 8, 6,
0, 0, 2, 2, 1, 1, 8, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 7, 7, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 5, 5, 4, 4, 9, 9, 0, 0, 5, 5, 4, 4, 9, 9,
/* DIFF24 */
0, 0, 2, 2, 1, 1, 6, 3, 0, 0, 2, 2, 1, 1, 3, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5,10, 4, 4, 3, 3, 0, 0, 5, 5,11, 4, 3, 3,
0, 0, 5,10, 4, 4, 3, 3, 0, 0, 5, 5,11, 4, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5,10, 4, 4, 3, 3, 0, 0, 5, 5,11, 4, 3, 3,
0, 0, 5,10, 4, 4, 3, 3, 0, 0, 5,10,11,11, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
/* DIFF26 DIFF24 */
0, 0, 2, 2, 1, 1, 6, 3, 0, 0, 2, 2, 1, 1, 3, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5,11, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5,11, 4, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5,11, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5,11,11, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
/* DIFF84 */
0, 0, 2, 2, 1, 1,13,13, 0, 0, 2, 2, 1, 1,13, 8,
0, 0, 2, 2, 1, 1,12, 6, 0, 0, 2, 2, 1, 1, 8, 8,
0, 0, 5,10, 4, 4,13,13, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 5,10, 4, 4,12,13, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 2, 2, 1, 1, 7, 8, 0, 0, 2, 2, 1, 1, 6, 8,
0, 0, 2, 2, 1, 1, 8, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5,10, 4, 4, 7,13, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 5,10, 4, 4, 9, 9, 0, 0, 5,10, 4, 4, 9, 9,
0, 0, 2, 2, 1, 1,13, 8, 0, 0, 2, 2, 1, 1, 8, 8,
0, 0, 2, 2, 1, 1,12, 8, 0, 0, 2, 2, 1, 1, 8, 6,
0, 0, 5, 5, 4, 4,13,13, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 5, 5, 4, 4,12,13, 0, 0, 5, 5, 4, 4,12,13,
0, 0, 2, 2, 1, 1, 7, 8, 0, 0, 2, 2, 1, 1, 8, 6,
0, 0, 2, 2, 1, 1, 8, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 7, 7, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 5, 5, 4, 4, 9, 9, 0, 0, 5, 5, 4, 4, 9, 9,
/* DIFF26 DIFF84 */
0, 0, 2, 2, 1, 1,13,13, 0, 0, 2, 2, 1, 1,13, 8,
0, 0, 2, 2, 1, 1,12, 6, 0, 0, 2, 2, 1, 1, 8, 8,
0, 0, 5, 5, 4, 4,13,13, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 5, 5, 4, 4,12,13, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 2, 2, 1, 1, 7, 8, 0, 0, 2, 2, 1, 1, 6, 8,
0, 0, 2, 2, 1, 1, 8, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 7,13, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 5, 5, 4, 4, 9, 9, 0, 0, 5, 5, 4, 4, 9, 9,
0, 0, 2, 2, 1, 1,13, 8, 0, 0, 2, 2, 1, 1, 8, 8,
0, 0, 2, 2, 1, 1,12, 8, 0, 0, 2, 2, 1, 1, 8, 6,
0, 0, 5, 5, 4, 4,13,13, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 5, 5, 4, 4,12,13, 0, 0, 5, 5, 4, 4,12,13,
0, 0, 2, 2, 1, 1, 7, 8, 0, 0, 2, 2, 1, 1, 8, 6,
0, 0, 2, 2, 1, 1, 8, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 7, 7, 0, 0, 5, 5, 4, 4,13,13,
0, 0, 5, 5, 4, 4, 9, 9, 0, 0, 5, 5, 4, 4, 9, 9,
/* DIFF24 DIFF84 */
0, 0, 2, 2, 1, 1, 6, 3, 0, 0, 2, 2, 1, 1, 3, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5,10, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5,10, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5,10, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5,10, 4, 4, 3, 3, 0, 0, 5,10, 4, 4, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
/* DIFF26 DIFF24 DIFF84 */
0, 0, 2, 2, 1, 1, 6, 3, 0, 0, 2, 2, 1, 1, 3, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 2, 2, 1, 1, 6, 6, 0, 0, 2, 2, 1, 1, 6, 6,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3,
0, 0, 5, 5, 4, 4, 3, 3, 0, 0, 5, 5, 4, 4, 3, 3};
#define RB(y,u,v) (((y)&0x3FF)<<22)|(((u)&0x3FF)<<11)|((v)&0x3FF)
#define GO(y,v) ((((y)+64)&0x3FF)<<22)|(16<<11)|(((v)+16)&0x3FF)
static const uint32_t DiffTable[128] = {
RB(-85, 160, 80), RB(-83, 155, 77), RB(-80, 150, 75), RB(-77, 145, 72),
RB(-75, 140, 70), RB(-72, 135, 67), RB(-69, 130, 65), RB(-67, 125, 62),
RB(-64, 120, 60), RB(-61, 115, 57), RB(-59, 110, 55), RB(-56, 105, 52),
RB(-53, 100, 50), RB(-51, 95, 47), RB(-48, 90, 45), RB(-45, 85, 42),
RB(-43, 80, 40), RB(-40, 75, 37), RB(-37, 70, 35), RB(-35, 65, 32),
RB(-32, 60, 30), RB(-29, 55, 27), RB(-27, 50, 25), RB(-24, 45, 22),
RB(-21, 40, 20), RB(-19, 35, 17), RB(-16, 30, 15), RB(-13, 25, 12),
RB(-11, 20, 10), RB( -8, 15, 7), RB( -5, 10, 5), RB( -3, 5, 2),
RB( 0, 0, 0), RB( 2, -5, -2), RB( 5, -10, -5), RB( 7, -15, -7),
RB( 10, -20, -10), RB( 13, -25, -12), RB( 15, -30, -15), RB( 18, -35, -17),
RB( 21, -40, -20), RB( 23, -45, -22), RB( 26, -50, -25), RB( 29, -55, -27),
RB( 31, -60, -30), RB( 34, -65, -32), RB( 37, -70, -35), RB( 39, -75, -37),
RB( 42, -80, -40), RB( 45, -85, -42), RB( 47, -90, -45), RB( 50, -95, -47),
RB( 53,-100, -50), RB( 55,-105, -52), RB( 58,-110, -55), RB( 61,-115, -57),
RB( 63,-120, -60), RB( 66,-125, -62), RB( 69,-130, -65), RB( 71,-135, -67),
RB( 74,-140, -70), RB( 77,-145, -72), RB( 79,-150, -75), RB( 82,-155, -77),
GO(-84, -160), GO(-81, -155), GO(-78, -150), GO(-76, -145),
GO(-73, -140), GO(-70, -135), GO(-68, -130), GO(-65, -125),
GO(-63, -120), GO(-60, -115), GO(-57, -110), GO(-55, -105),
GO(-52, -100), GO(-49, -95), GO(-47, -90), GO(-44, -85),
GO(-42, -80), GO(-39, -75), GO(-36, -70), GO(-34, -65),
GO(-31, -60), GO(-28, -55), GO(-26, -50), GO(-23, -45),
GO(-21, -40), GO(-18, -35), GO(-15, -30), GO(-13, -25),
GO(-10, -20), GO( -7, -15), GO( -5, -10), GO( -2, -5),
GO( 0, 0), GO( 2, 4), GO( 5, 9), GO( 7, 14),
GO( 10, 19), GO( 13, 24), GO( 15, 29), GO( 18, 34),
GO( 21, 39), GO( 23, 44), GO( 26, 49), GO( 28, 54),
GO( 31, 59), GO( 34, 64), GO( 36, 69), GO( 39, 74),
GO( 42, 79), GO( 44, 84), GO( 47, 89), GO( 49, 94),
GO( 52, 99), GO( 55, 104), GO( 57, 109), GO( 60, 114),
GO( 63, 119), GO( 65, 124), GO( 68, 129), GO( 70, 134),
GO( 73, 139), GO( 76, 144), GO( 78, 149), GO( 81, 154)};
inline static int ExpandedDiff (uint32_t c0, uint32_t c1) {
uint32_t r, g;
g = c0;
g += 0x4008020;
g -= c1;
r = DiffTable[(int)((unsigned char)g) + 0];
r ^= (0x3FF << 11);
g >>= 10;
r += DiffTable[(int)((unsigned char)g) + 0];
g >>= 11;
r += DiffTable[(int)((unsigned char)g) + 64];
r &= 0xE01F03E0;
return r;
}
#define DIFF56 0x001
#define DIFF52 0x002
#define DIFF54 0x004
#define DIFF58 0x008
#define DIFF53 0x010
#define DIFF51 0x020
#define DIFF57 0x040
#define DIFF59 0x080
#define DIFF26 0x100
#define DIFF24 0x200
#define DIFF84 0x400
#define DIFF86 0x800
/* lastLineDiffs is previous line's 52, 53, 26, all >> 1 */
static uint8_t lastLineDiffs[__PAST_LIBRARY_WIDTH];
#define RotatePattern(x) ((((x) & 0x777) << 1) | (((x) & 0x888) >> 3))
void ProcessHQ2x(const pixel * restrict in, pixel * restrict out) {
signed int y, x;
unsigned int pattern, newpattern;
uint32_t pixels[9];
int prevline, nextline;
memset(lastLineDiffs, 0, sizeof(lastLineDiffs));
prevline = 1;
nextline = 1 + __PAST_LIBRARY_WIDTH;
y = __PAST_LIBRARY_HEIGHT - 1;
do {
pixels[1-1] =
pixels[2-1] = RGBUnpack(in[prevline-1]); /* Pixel 2 */
pixels[3-1] = RGBUnpack(in[prevline ]); /* Pixel 3 */
pixels[4-1] =
pixels[5-1] = RGBUnpack(in[ 0]); /* Pixel 5 */
pixels[6-1] = RGBUnpack(in[ 1]); /* Pixel 6 */
pixels[7-1] =
pixels[8-1] = RGBUnpack(in[nextline-1]); /* Pixel 8 */
pixels[9-1] = RGBUnpack(in[nextline ]); /* Pixel 9 */
pattern = 0;
x = __PAST_LIBRARY_WIDTH - 1;
do {
newpattern = 0;
if (pattern & DIFF26) newpattern |= DIFF51;
if (pattern & DIFF56) newpattern |= DIFF54;
if (pattern & DIFF86) newpattern |= DIFF57;
if (pattern & DIFF53) newpattern |= DIFF24;
if (pattern & DIFF59) newpattern |= DIFF84;
if (lastLineDiffs[x] & (DIFF52 >> 1)) newpattern |= DIFF58;
if (lastLineDiffs[x] & (DIFF26 >> 1)) newpattern |= DIFF59;
if (lastLineDiffs[x] & (DIFF53 >> 1)) newpattern |= DIFF86;
pattern = newpattern;
if (ExpandedDiff(pixels[5-1], pixels[2-1])) pattern |= DIFF52;
if (ExpandedDiff(pixels[5-1], pixels[3-1])) pattern |= DIFF53;
if (ExpandedDiff(pixels[5-1], pixels[6-1])) pattern |= DIFF56;
if (ExpandedDiff(pixels[2-1], pixels[6-1])) pattern |= DIFF26;
lastLineDiffs[x] = pattern >> 1;
newpattern = tree_hq[pattern & 0x7FF];
pattern = RotatePattern(pattern);
out[ 0] =
RGBPack(((pixels[5-1] * blends_2x[(newpattern * 4) + 0]) +
(pixels[2-1] * blends_2x[(newpattern * 4) + 1]) +
(pixels[4-1] * blends_2x[(newpattern * 4) + 2]) +
(pixels[1-1] * blends_2x[(newpattern * 4) + 3])) / 16);
newpattern = tree_hq[pattern & 0x7FF];
pattern = RotatePattern(pattern);
out[ 1] =
RGBPack(((pixels[5-1] * blends_2x[(newpattern * 4) + 0]) +
(pixels[6-1] * blends_2x[(newpattern * 4) + 1]) +
(pixels[2-1] * blends_2x[(newpattern * 4) + 2]) +
(pixels[3-1] * blends_2x[(newpattern * 4) + 3])) / 16);
newpattern = tree_hq[pattern & 0x7FF];
pattern = RotatePattern(pattern);
out[(__PAST_LIBRARY_WIDTH*2)+1] =
RGBPack(((pixels[5-1] * blends_2x[(newpattern * 4) + 0]) +
(pixels[8-1] * blends_2x[(newpattern * 4) + 1]) +
(pixels[6-1] * blends_2x[(newpattern * 4) + 2]) +
(pixels[9-1] * blends_2x[(newpattern * 4) + 3])) / 16);
newpattern = tree_hq[pattern & 0x7FF];
pattern = RotatePattern(pattern);
out[(__PAST_LIBRARY_WIDTH*2) ] =
RGBPack(((pixels[5-1] * blends_2x[(newpattern * 4) + 0]) +
(pixels[4-1] * blends_2x[(newpattern * 4) + 1]) +
(pixels[8-1] * blends_2x[(newpattern * 4) + 2]) +
(pixels[7-1] * blends_2x[(newpattern * 4) + 3])) / 16);
out += 2;
in++;
x--;
if (x == 0) {
pixels[1-1] = pixels[2-1];
pixels[2-1] = pixels[3-1];
pixels[4-1] = pixels[5-1];
pixels[5-1] = pixels[6-1];
pixels[7-1] = pixels[8-1];
pixels[8-1] = pixels[9-1];
continue;
}
pixels[1-1] = pixels[2-1];
pixels[2-1] = pixels[3-1];
pixels[3-1] = RGBUnpack(in[prevline]); /* Pixel 3 */
pixels[4-1] = pixels[5-1];
pixels[5-1] = pixels[6-1];
pixels[6-1] = RGBUnpack(in[1 ]); /* Pixel 6 */
pixels[7-1] = pixels[8-1];
pixels[8-1] = pixels[9-1];
pixels[9-1] = RGBUnpack(in[nextline]); /* Pixel 9 */
} while (x >= 0);
prevline = 1 - __PAST_LIBRARY_WIDTH;
out += (__PAST_LIBRARY_WIDTH * 2);
y--;
if (y > 0) {
continue;
}
nextline = 0;
} while (y >= 0);
}
void ProcessHQ4x(const pixel * restrict in, pixel * restrict out) {
signed int y, x;
unsigned int pattern, newpattern;
uint32_t pixels[9];
int prevline, nextline;
memset(lastLineDiffs, 0, sizeof(lastLineDiffs));
prevline = 1;
nextline = 1 + __PAST_LIBRARY_WIDTH;
y = __PAST_LIBRARY_HEIGHT - 1;
do {
pixels[1-1] =
pixels[2-1] = RGBUnpack(in[prevline-1]); /* Pixel 2 */
pixels[3-1] = RGBUnpack(in[prevline ]); /* Pixel 3 */
pixels[4-1] =
pixels[5-1] = RGBUnpack(in[ 0]); /* Pixel 5 */
pixels[6-1] = RGBUnpack(in[ 1]); /* Pixel 6 */
pixels[7-1] =
pixels[8-1] = RGBUnpack(in[nextline-1]); /* Pixel 8 */
pixels[9-1] = RGBUnpack(in[nextline ]); /* Pixel 9 */
pattern = 0;
x = __PAST_LIBRARY_WIDTH - 1;
do {
newpattern = 0;
if (pattern & DIFF26) newpattern |= DIFF51;
if (pattern & DIFF56) newpattern |= DIFF54;
if (pattern & DIFF86) newpattern |= DIFF57;
if (pattern & DIFF53) newpattern |= DIFF24;
if (pattern & DIFF59) newpattern |= DIFF84;
if (lastLineDiffs[x] & (DIFF52 >> 1)) newpattern |= DIFF58;
if (lastLineDiffs[x] & (DIFF26 >> 1)) newpattern |= DIFF59;
if (lastLineDiffs[x] & (DIFF53 >> 1)) newpattern |= DIFF86;
pattern = newpattern;
if (ExpandedDiff(pixels[5-1], pixels[2-1])) pattern |= DIFF52;
if (ExpandedDiff(pixels[5-1], pixels[3-1])) pattern |= DIFF53;
if (ExpandedDiff(pixels[5-1], pixels[6-1])) pattern |= DIFF56;
if (ExpandedDiff(pixels[2-1], pixels[6-1])) pattern |= DIFF26;
lastLineDiffs[x] = pattern >> 1;
newpattern = tree_hq[pattern & 0x7FF];
pattern = RotatePattern(pattern);
out[ 0] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x0]) +
(pixels[2-1] * blends_4x[(newpattern * 16) + 1 + 0x0]) +
(pixels[4-1] * blends_4x[(newpattern * 16) + 2 + 0x0]) +
(pixels[1-1] * blends_4x[(newpattern * 16) + 3 + 0x0])) / 16);
out[ 1] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x4]) +
(pixels[2-1] * blends_4x[(newpattern * 16) + 1 + 0x4]) +
(pixels[4-1] * blends_4x[(newpattern * 16) + 2 + 0x4]) +
(pixels[1-1] * blends_4x[(newpattern * 16) + 3 + 0x4])) / 16);
out[(__PAST_LIBRARY_WIDTH*0x4) ] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x8]) +
(pixels[2-1] * blends_4x[(newpattern * 16) + 1 + 0x8]) +
(pixels[4-1] * blends_4x[(newpattern * 16) + 2 + 0x8]) +
(pixels[1-1] * blends_4x[(newpattern * 16) + 3 + 0x8])) / 16);
out[(__PAST_LIBRARY_WIDTH*0x4)+1] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0xC]) +
(pixels[2-1] * blends_4x[(newpattern * 16) + 1 + 0xC]) +
(pixels[4-1] * blends_4x[(newpattern * 16) + 2 + 0xC]) +
(pixels[1-1] * blends_4x[(newpattern * 16) + 3 + 0xC])) / 16);
newpattern = tree_hq[pattern & 0x7FF];
pattern = RotatePattern(pattern);
out[ 3] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x0]) +
(pixels[6-1] * blends_4x[(newpattern * 16) + 1 + 0x0]) +
(pixels[2-1] * blends_4x[(newpattern * 16) + 2 + 0x0]) +
(pixels[3-1] * blends_4x[(newpattern * 16) + 3 + 0x0])) / 16);
out[(__PAST_LIBRARY_WIDTH*0x4)+3] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x4]) +
(pixels[6-1] * blends_4x[(newpattern * 16) + 1 + 0x4]) +
(pixels[2-1] * blends_4x[(newpattern * 16) + 2 + 0x4]) +
(pixels[3-1] * blends_4x[(newpattern * 16) + 3 + 0x4])) / 16);
out[ 2] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x8]) +
(pixels[6-1] * blends_4x[(newpattern * 16) + 1 + 0x8]) +
(pixels[2-1] * blends_4x[(newpattern * 16) + 2 + 0x8]) +
(pixels[3-1] * blends_4x[(newpattern * 16) + 3 + 0x8])) / 16);
out[(__PAST_LIBRARY_WIDTH*0x4)+2] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0xC]) +
(pixels[6-1] * blends_4x[(newpattern * 16) + 1 + 0xC]) +
(pixels[2-1] * blends_4x[(newpattern * 16) + 2 + 0xC]) +
(pixels[3-1] * blends_4x[(newpattern * 16) + 3 + 0xC])) / 16);
newpattern = tree_hq[pattern & 0x7FF];
pattern = RotatePattern(pattern);
out[(__PAST_LIBRARY_WIDTH*0xC)+3] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x0]) +
(pixels[8-1] * blends_4x[(newpattern * 16) + 1 + 0x0]) +
(pixels[6-1] * blends_4x[(newpattern * 16) + 2 + 0x0]) +
(pixels[9-1] * blends_4x[(newpattern * 16) + 3 + 0x0])) / 16);
out[(__PAST_LIBRARY_WIDTH*0xC)+2] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x4]) +
(pixels[8-1] * blends_4x[(newpattern * 16) + 1 + 0x4]) +
(pixels[6-1] * blends_4x[(newpattern * 16) + 2 + 0x4]) +
(pixels[9-1] * blends_4x[(newpattern * 16) + 3 + 0x4])) / 16);
out[(__PAST_LIBRARY_WIDTH*0x8)+3] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x8]) +
(pixels[8-1] * blends_4x[(newpattern * 16) + 1 + 0x8]) +
(pixels[6-1] * blends_4x[(newpattern * 16) + 2 + 0x8]) +
(pixels[9-1] * blends_4x[(newpattern * 16) + 3 + 0x8])) / 16);
out[(__PAST_LIBRARY_WIDTH*0x8)+2] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0xC]) +
(pixels[8-1] * blends_4x[(newpattern * 16) + 1 + 0xC]) +
(pixels[6-1] * blends_4x[(newpattern * 16) + 2 + 0xC]) +
(pixels[9-1] * blends_4x[(newpattern * 16) + 3 + 0xC])) / 16);
newpattern = tree_hq[pattern & 0x7FF];
pattern = RotatePattern(pattern);
out[(__PAST_LIBRARY_WIDTH*0xC) ] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x0]) +
(pixels[4-1] * blends_4x[(newpattern * 16) + 1 + 0x0]) +
(pixels[8-1] * blends_4x[(newpattern * 16) + 2 + 0x0]) +
(pixels[7-1] * blends_4x[(newpattern * 16) + 3 + 0x0])) / 16);
out[(__PAST_LIBRARY_WIDTH*0x8) ] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x4]) +
(pixels[4-1] * blends_4x[(newpattern * 16) + 1 + 0x4]) +
(pixels[8-1] * blends_4x[(newpattern * 16) + 2 + 0x4]) +
(pixels[7-1] * blends_4x[(newpattern * 16) + 3 + 0x4])) / 16);
out[(__PAST_LIBRARY_WIDTH*0xC)+1] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0x8]) +
(pixels[4-1] * blends_4x[(newpattern * 16) + 1 + 0x8]) +
(pixels[8-1] * blends_4x[(newpattern * 16) + 2 + 0x8]) +
(pixels[7-1] * blends_4x[(newpattern * 16) + 3 + 0x8])) / 16);
out[(__PAST_LIBRARY_WIDTH*0x8)+1] =
RGBPack(((pixels[5-1] * blends_4x[(newpattern * 16) + 0 + 0xC]) +
(pixels[4-1] * blends_4x[(newpattern * 16) + 1 + 0xC]) +
(pixels[8-1] * blends_4x[(newpattern * 16) + 2 + 0xC]) +
(pixels[7-1] * blends_4x[(newpattern * 16) + 3 + 0xC])) / 16);
out += 4;
in++;
x--;
if (x == 0) {
pixels[1-1] = pixels[2-1];
pixels[2-1] = pixels[3-1];
pixels[4-1] = pixels[5-1];
pixels[5-1] = pixels[6-1];
pixels[7-1] = pixels[8-1];
pixels[8-1] = pixels[9-1];
continue;
}
pixels[1-1] = pixels[2-1];
pixels[2-1] = pixels[3-1];
pixels[3-1] = RGBUnpack(in[prevline]); /* Pixel 3 */
pixels[4-1] = pixels[5-1];
pixels[5-1] = pixels[6-1];
pixels[6-1] = RGBUnpack(in[1 ]); /* Pixel 6 */
pixels[7-1] = pixels[8-1];
pixels[8-1] = pixels[9-1];
pixels[9-1] = RGBUnpack(in[nextline]); /* Pixel 9 */
} while (x >= 0);
prevline = 1 - __PAST_LIBRARY_WIDTH;
out += (__PAST_LIBRARY_WIDTH * 0xC);
y--;
if (y > 0) {
continue;
}
nextline = 0;
} while (y >= 0);
}

View File

@ -1,19 +0,0 @@
#include "ntsc.h"
#include <stdlib.h>
#include <stdbool.h>
void ntsc_filter(uint16_t * restrict out, const uint16_t * restrict in, int width, int height)
{
static int phase = 0;
static snes_ntsc_t ntsc;
static bool inited = false;
if (inited == false)
{
snes_ntsc_init(&ntsc, &snes_ntsc_composite);
inited = true;
}
snes_ntsc_blit(&ntsc, in, width, phase, width, height, out, SNES_NTSC_OUT_WIDTH(width) * sizeof(uint16_t));
phase ^= 1;
}

View File

@ -1,9 +0,0 @@
#ifndef _NTSC_FILTER_H
#define _NTSC_FILTER_H
#include <stdint.h>
#include "snes_ntsc/snes_ntsc.h"
void ntsc_filter(uint16_t * restrict out, const uint16_t * restrict in, int width, int height);
#endif

View File

@ -1,54 +0,0 @@
/* This source code is Copyright (C) 2006-2009 by WolfWings. */
/* It is, however, released under the ISC license. */
/* en.wikipedia.org/wiki/ISC_Licence */
/* --------------------------------------------------------- */
/* It is a formula-level rederiviation of the HQ2x technique */
/* and is, thus, not a derivative work of the original code, */
/* only the original equations behind the code. */
#ifndef __PAST_LIBRARY_H
#define __PAST_LIBRARY_H
#include <stdint.h>
#ifndef __PAST_LIBRARY_WIDTH
#define __PAST_LIBRARY_WIDTH 256
#endif
#ifndef __PAST_LIBRARY_HEIGHT
#define __PAST_LIBRARY_HEIGHT 224
#endif
typedef uint16_t pixel;
/* These two functions are what need to be modified to interface other
* pixel formats with the library. They need to return values inside a
* format like this: (Red/Blue can be reversed.)
*
* 0000-00GG-GGG0-0000-0RRR-RR00-000B-BBBB
*
* This is VERY fast to create from 15-bit (NOT 16-bit) RGB/BGR, as
* below.
*
* If you can't return data in this format, you'll have to rebuild the
* ExpandedDiff function and DiffTable array to compensate, and possibly
* change the blending functions in the Process* functions to handle any
* guard-bits and masking.
*/
static inline uint32_t RGBUnpack(pixel i) {
uint32_t o = i;
o = (o * 0x10001);
o = o & 0x03E07C1F;
return o;
}
static inline pixel RGBPack(uint32_t x) {
x &= 0x03E07C1F;
x |= (x >> 16);
return x;
}
void ProcessHQ2x(const pixel * restrict inbuffer, pixel * restrict outbuffer);
void ProcessHQ4x(const pixel * restrict inbuffer, pixel * restrict outbuffer);
#endif /* __PAST_LIBRARY_H */

View File

@ -1,251 +0,0 @@
/* snes_ntsc 0.2.2. http://www.slack.net/~ant/ */
#include "snes_ntsc.h"
/* Copyright (C) 2006-2007 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module 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 Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
snes_ntsc_setup_t const snes_ntsc_monochrome = { 0,-1, 0, 0,.2, 0,.2,-.2,-.2,-1, 1, 0, 0 };
snes_ntsc_setup_t const snes_ntsc_composite = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 };
snes_ntsc_setup_t const snes_ntsc_svideo = { 0, 0, 0, 0,.2, 0,.2, -1, -1, 0, 1, 0, 0 };
snes_ntsc_setup_t const snes_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.7, -1, -1,-1, 1, 0, 0 };
#define alignment_count 3
#define burst_count 3
#define rescale_in 8
#define rescale_out 7
#define artifacts_mid 1.0f
#define fringing_mid 1.0f
#define std_decoder_hue 0
#define rgb_bits 7 /* half normal range to allow for doubled hires pixels */
#define gamma_size 32
#include "snes_ntsc_impl.h"
/* 3 input pixels -> 8 composite samples */
pixel_info_t const snes_ntsc_pixels [alignment_count] = {
{ PIXEL_OFFSET( -4, -9 ), { 1, 1, .6667f, 0 } },
{ PIXEL_OFFSET( -2, -7 ), { .3333f, 1, 1, .3333f } },
{ PIXEL_OFFSET( 0, -5 ), { 0, .6667f, 1, 1 } },
};
static void merge_kernel_fields( snes_ntsc_rgb_t* io )
{
int n;
for ( n = burst_size; n; --n )
{
snes_ntsc_rgb_t p0 = io [burst_size * 0] + rgb_bias;
snes_ntsc_rgb_t p1 = io [burst_size * 1] + rgb_bias;
snes_ntsc_rgb_t p2 = io [burst_size * 2] + rgb_bias;
/* merge colors without losing precision */
io [burst_size * 0] =
((p0 + p1 - ((p0 ^ p1) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
io [burst_size * 1] =
((p1 + p2 - ((p1 ^ p2) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
io [burst_size * 2] =
((p2 + p0 - ((p2 ^ p0) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
++io;
}
}
static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out )
{
int n;
for ( n = burst_count; n; --n )
{
unsigned i;
for ( i = 0; i < rgb_kernel_size / 2; i++ )
{
snes_ntsc_rgb_t error = color -
out [i ] - out [(i+12)%14+14] - out [(i+10)%14+28] -
out [i + 7] - out [i + 5 +14] - out [i + 3 +28];
DISTRIBUTE_ERROR( i+3+28, i+5+14, i+7 );
}
out += alignment_count * rgb_kernel_size;
}
}
void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup )
{
int merge_fields;
int entry;
init_t impl;
if ( !setup )
setup = &snes_ntsc_composite;
init( &impl, setup );
merge_fields = setup->merge_fields;
if ( setup->artifacts <= -1 && setup->fringing <= -1 )
merge_fields = 1;
for ( entry = 0; entry < snes_ntsc_palette_size; entry++ )
{
/* Reduce number of significant bits of source color. Clearing the
low bits of R and B were least notictable. Modifying green was too
noticeable. */
int ir = entry >> 8 & 0x1E;
int ig = entry >> 4 & 0x1F;
int ib = entry << 1 & 0x1E;
#if SNES_NTSC_BSNES_COLORTBL
if ( setup->bsnes_colortbl )
{
int bgr15 = (ib << 10) | (ig << 5) | ir;
unsigned long rgb16 = setup->bsnes_colortbl [bgr15];
ir = rgb16 >> 11 & 0x1E;
ig = rgb16 >> 6 & 0x1F;
ib = rgb16 & 0x1E;
}
#endif
{
float rr = impl.to_float [ir];
float gg = impl.to_float [ig];
float bb = impl.to_float [ib];
float y, i, q = RGB_TO_YIQ( rr, gg, bb, y, i );
int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g );
snes_ntsc_rgb_t rgb = PACK_RGB( r, g, b );
snes_ntsc_rgb_t* out = ntsc->table [entry];
gen_kernel( &impl, y, i, q, out );
if ( merge_fields )
merge_kernel_fields( out );
correct_errors( rgb, out );
}
}
}
#ifndef SNES_NTSC_NO_BLITTERS
void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width,
int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch )
{
int chunk_count = (in_width - 1) / snes_ntsc_in_chunk;
for ( ; in_height; --in_height )
{
SNES_NTSC_IN_T const* line_in = input;
SNES_NTSC_BEGIN_ROW( ntsc, burst_phase,
snes_ntsc_black, snes_ntsc_black, SNES_NTSC_ADJ_IN( *line_in ) );
snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out;
int n;
++line_in;
for ( n = chunk_count; n; --n )
{
/* order of input and output pixels must not be altered */
SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) );
SNES_NTSC_RGB_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) );
SNES_NTSC_RGB_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) );
SNES_NTSC_RGB_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
line_in += 3;
line_out += 7;
}
/* finish final pixels */
SNES_NTSC_COLOR_IN( 0, snes_ntsc_black );
SNES_NTSC_RGB_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 1, snes_ntsc_black );
SNES_NTSC_RGB_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 2, snes_ntsc_black );
SNES_NTSC_RGB_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
burst_phase = (burst_phase + 1) % snes_ntsc_burst_count;
input += in_row_width;
rgb_out = (char*) rgb_out + out_pitch;
}
}
void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width,
int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch )
{
int chunk_count = (in_width - 2) / (snes_ntsc_in_chunk * 2);
for ( ; in_height; --in_height )
{
SNES_NTSC_IN_T const* line_in = input;
SNES_NTSC_HIRES_ROW( ntsc, burst_phase,
snes_ntsc_black, snes_ntsc_black, snes_ntsc_black,
SNES_NTSC_ADJ_IN( line_in [0] ),
SNES_NTSC_ADJ_IN( line_in [1] ) );
snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out;
int n;
line_in += 2;
for ( n = chunk_count; n; --n )
{
/* twice as many input pixels per chunk */
SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) );
SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) );
SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) );
SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 3, SNES_NTSC_ADJ_IN( line_in [3] ) );
SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 4, SNES_NTSC_ADJ_IN( line_in [4] ) );
SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 5, SNES_NTSC_ADJ_IN( line_in [5] ) );
SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
line_in += 6;
line_out += 7;
}
SNES_NTSC_COLOR_IN( 0, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 1, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 2, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 3, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 4, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 5, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
burst_phase = (burst_phase + 1) % snes_ntsc_burst_count;
input += in_row_width;
rgb_out = (char*) rgb_out + out_pitch;
}
}
#endif

View File

@ -1,236 +0,0 @@
/* SNES NTSC video filter */
/* snes_ntsc 0.2.2 */
#ifndef SNES_NTSC_H
#define SNES_NTSC_H
#include "snes_ntsc_config.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown
in parenthesis and should remain fairly stable in future versions. */
typedef struct snes_ntsc_setup_t
{
/* Basic parameters */
double hue; /* -1 = -180 degrees +1 = +180 degrees */
double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */
double contrast; /* -1 = dark (0.5) +1 = light (1.5) */
double brightness; /* -1 = dark (0.5) +1 = light (1.5) */
double sharpness; /* edge contrast enhancement/blurring */
/* Advanced parameters */
double gamma; /* -1 = dark (1.5) +1 = light (0.5) */
double resolution; /* image resolution */
double artifacts; /* artifacts caused by color changes */
double fringing; /* color artifacts caused by brightness changes */
double bleed; /* color bleed (color resolution reduction) */
int merge_fields; /* if 1, merges even and odd fields together to reduce flicker */
float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */
unsigned long const* bsnes_colortbl; /* undocumented; set to 0 */
} snes_ntsc_setup_t;
/* Video format presets */
extern snes_ntsc_setup_t const snes_ntsc_composite; /* color bleeding + artifacts */
extern snes_ntsc_setup_t const snes_ntsc_svideo; /* color bleeding only */
extern snes_ntsc_setup_t const snes_ntsc_rgb; /* crisp image */
extern snes_ntsc_setup_t const snes_ntsc_monochrome;/* desaturated + artifacts */
/* Initializes and adjusts parameters. Can be called multiple times on the same
snes_ntsc_t object. Can pass NULL for either parameter. */
typedef struct snes_ntsc_t snes_ntsc_t;
void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup );
/* Filters one or more rows of pixels. Input pixel format is set by SNES_NTSC_IN_FORMAT
and output RGB depth is set by SNES_NTSC_OUT_DEPTH. Both default to 16-bit RGB.
In_row_width is the number of pixels to get to the next input row. Out_pitch
is the number of *bytes* to get to the next output row. */
void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input,
long in_row_width, int burst_phase, int in_width, int in_height,
void* rgb_out, long out_pitch );
void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input,
long in_row_width, int burst_phase, int in_width, int in_height,
void* rgb_out, long out_pitch );
/* Number of output pixels written by low-res blitter for given input width. Width
might be rounded down slightly; use SNES_NTSC_IN_WIDTH() on result to find rounded
value. Guaranteed not to round 256 down at all. */
#define SNES_NTSC_OUT_WIDTH( in_width ) \
((((in_width) - 1) / snes_ntsc_in_chunk + 1) * snes_ntsc_out_chunk)
/* Number of low-res input pixels that will fit within given output width. Might be
rounded down slightly; use SNES_NTSC_OUT_WIDTH() on result to find rounded
value. */
#define SNES_NTSC_IN_WIDTH( out_width ) \
(((out_width) / snes_ntsc_out_chunk - 1) * snes_ntsc_in_chunk + 1)
/* Interface for user-defined custom blitters */
enum { snes_ntsc_in_chunk = 3 }; /* number of input pixels read per chunk */
enum { snes_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */
enum { snes_ntsc_black = 0 }; /* palette index for black */
enum { snes_ntsc_burst_count = 3 }; /* burst phase cycles through 0, 1, and 2 */
/* Begins outputting row and starts three pixels. First pixel will be cut off a bit.
Use snes_ntsc_black for unused pixels. Declares variables, so must be before first
statement in a block (unless you're using C++). */
#define SNES_NTSC_BEGIN_ROW( ntsc, burst, pixel0, pixel1, pixel2 ) \
char const* ktable = \
(char const*) (ntsc)->table + burst * (snes_ntsc_burst_size * sizeof (snes_ntsc_rgb_t));\
SNES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, SNES_NTSC_IN_FORMAT, ktable )
/* Begins input pixel */
#define SNES_NTSC_COLOR_IN( index, color ) \
SNES_NTSC_COLOR_IN_( index, color, SNES_NTSC_IN_FORMAT, ktable )
/* Generates output pixel. Bits can be 24, 16, 15, 14, 32 (treated as 24), or 0:
24: RRRRRRRR GGGGGGGG BBBBBBBB (8-8-8 RGB)
16: RRRRRGGG GGGBBBBB (5-6-5 RGB)
15: RRRRRGG GGGBBBBB (5-5-5 RGB)
14: BBBBBGG GGGRRRRR (5-5-5 BGR, native SNES format)
0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */
#define SNES_NTSC_RGB_OUT( index, rgb_out, bits ) \
SNES_NTSC_RGB_OUT_14_( index, rgb_out, bits, 1 )
/* Hires equivalents */
#define SNES_NTSC_HIRES_ROW( ntsc, burst, pixel1, pixel2, pixel3, pixel4, pixel5 ) \
char const* ktable = \
(char const*) (ntsc)->table + burst * (snes_ntsc_burst_size * sizeof (snes_ntsc_rgb_t));\
unsigned const snes_ntsc_pixel1_ = (pixel1);\
snes_ntsc_rgb_t const* kernel1 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel1_ );\
unsigned const snes_ntsc_pixel2_ = (pixel2);\
snes_ntsc_rgb_t const* kernel2 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel2_ );\
unsigned const snes_ntsc_pixel3_ = (pixel3);\
snes_ntsc_rgb_t const* kernel3 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel3_ );\
unsigned const snes_ntsc_pixel4_ = (pixel4);\
snes_ntsc_rgb_t const* kernel4 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel4_ );\
unsigned const snes_ntsc_pixel5_ = (pixel5);\
snes_ntsc_rgb_t const* kernel5 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel5_ );\
snes_ntsc_rgb_t const* kernel0 = kernel1;\
snes_ntsc_rgb_t const* kernelx0;\
snes_ntsc_rgb_t const* kernelx1 = kernel1;\
snes_ntsc_rgb_t const* kernelx2 = kernel1;\
snes_ntsc_rgb_t const* kernelx3 = kernel1;\
snes_ntsc_rgb_t const* kernelx4 = kernel1;\
snes_ntsc_rgb_t const* kernelx5 = kernel1
#define SNES_NTSC_HIRES_OUT( x, rgb_out, bits ) {\
snes_ntsc_rgb_t raw_ =\
kernel0 [ x ] + kernel2 [(x+5)%7+14] + kernel4 [(x+3)%7+28] +\
kernelx0 [(x+7)%7+7] + kernelx2 [(x+5)%7+21] + kernelx4 [(x+3)%7+35] +\
kernel1 [(x+6)%7 ] + kernel3 [(x+4)%7+14] + kernel5 [(x+2)%7+28] +\
kernelx1 [(x+6)%7+7] + kernelx3 [(x+4)%7+21] + kernelx5 [(x+2)%7+35];\
SNES_NTSC_CLAMP_( raw_, 0 );\
SNES_NTSC_RGB_OUT_( rgb_out, (bits), 0 );\
}
/* private */
enum { snes_ntsc_entry_size = 128 };
enum { snes_ntsc_palette_size = 0x2000 };
typedef unsigned long snes_ntsc_rgb_t;
struct snes_ntsc_t {
snes_ntsc_rgb_t table [snes_ntsc_palette_size] [snes_ntsc_entry_size];
};
enum { snes_ntsc_burst_size = snes_ntsc_entry_size / snes_ntsc_burst_count };
#define SNES_NTSC_RGB16( ktable, n ) \
(snes_ntsc_rgb_t const*) (ktable + ((n & 0x001E) | (n >> 1 & 0x03E0) | (n >> 2 & 0x3C00)) * \
(snes_ntsc_entry_size / 2 * sizeof (snes_ntsc_rgb_t)))
#define SNES_NTSC_BGR15( ktable, n ) \
(snes_ntsc_rgb_t const*) (ktable + ((n << 9 & 0x3C00) | (n & 0x03E0) | (n >> 10 & 0x001E)) * \
(snes_ntsc_entry_size / 2 * sizeof (snes_ntsc_rgb_t)))
/* common 3->7 ntsc macros */
#define SNES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, ENTRY, table ) \
unsigned const snes_ntsc_pixel0_ = (pixel0);\
snes_ntsc_rgb_t const* kernel0 = ENTRY( table, snes_ntsc_pixel0_ );\
unsigned const snes_ntsc_pixel1_ = (pixel1);\
snes_ntsc_rgb_t const* kernel1 = ENTRY( table, snes_ntsc_pixel1_ );\
unsigned const snes_ntsc_pixel2_ = (pixel2);\
snes_ntsc_rgb_t const* kernel2 = ENTRY( table, snes_ntsc_pixel2_ );\
snes_ntsc_rgb_t const* kernelx0;\
snes_ntsc_rgb_t const* kernelx1 = kernel0;\
snes_ntsc_rgb_t const* kernelx2 = kernel0
#define SNES_NTSC_RGB_OUT_14_( x, rgb_out, bits, shift ) {\
snes_ntsc_rgb_t raw_ =\
kernel0 [x ] + kernel1 [(x+12)%7+14] + kernel2 [(x+10)%7+28] +\
kernelx0 [(x+7)%14] + kernelx1 [(x+ 5)%7+21] + kernelx2 [(x+ 3)%7+35];\
SNES_NTSC_CLAMP_( raw_, shift );\
SNES_NTSC_RGB_OUT_( rgb_out, bits, shift );\
}
/* common ntsc macros */
#define snes_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1))
#define snes_ntsc_clamp_mask (snes_ntsc_rgb_builder * 3 / 2)
#define snes_ntsc_clamp_add (snes_ntsc_rgb_builder * 0x101)
#define SNES_NTSC_CLAMP_( io, shift ) {\
snes_ntsc_rgb_t sub = (io) >> (9-(shift)) & snes_ntsc_clamp_mask;\
snes_ntsc_rgb_t clamp = snes_ntsc_clamp_add - sub;\
io |= clamp;\
clamp -= sub;\
io &= clamp;\
}
#define SNES_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\
unsigned color_;\
kernelx##index = kernel##index;\
kernel##index = (color_ = (color), ENTRY( table, color_ ));\
}
/* x is always zero except in snes_ntsc library */
/* original routine */
#if 0
#define SNES_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
if ( bits == 16 )\
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
if ( bits == 24 || bits == 32 )\
rgb_out = (raw_>>(5-x)&0xFF0000)|(raw_>>(3-x)&0xFF00)|(raw_>>(1-x)&0xFF);\
if ( bits == 15 )\
rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\
if ( bits == 14 )\
rgb_out = (raw_>>(24-x)& 0x001F)|(raw_>>(9-x)&0x03E0)|(raw_<<(6+x)&0x7C00);\
if ( bits == 0 )\
rgb_out = raw_ << x;\
}
#endif
#define SNES_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\
}
// Custom SSNES routine for 15 bit.
/* custom bsnes routine -- hooks into bsnes colortable */
#if 0
#define SNES_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
if ( bits == 16 ) {\
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
rgb_out = ((rgb_out&0xf800)>>11)|((rgb_out&0x07c0)>>1)|((rgb_out&0x001f)<<10);\
rgb_out = colortable[rgb_out];\
} else if ( bits == 24 || bits == 32 ) {\
rgb_out = (raw_>>(5-x)&0xFF0000)|(raw_>>(3-x)&0xFF00)|(raw_>>(1-x)&0xFF);\
rgb_out = ((rgb_out&0xf80000)>>19)|((rgb_out&0x00f800)>>6)|((rgb_out&0x0000f8)<<7);\
rgb_out = colortable[rgb_out];\
} else if ( bits == 15 ) {\
rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\
rgb_out = ((rgb_out&0x7c00)>>10)|((rgb_out&0x03e0))|((rgb_out&0x001f)<<10);\
rgb_out = colortable[rgb_out];\
} else {\
rgb_out = raw_ << x;\
}\
}
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,27 +0,0 @@
/* Configure library by modifying this file */
#ifndef SNES_NTSC_CONFIG_H
#define SNES_NTSC_CONFIG_H
/* Format of source pixels */
/* #define SNES_NTSC_IN_FORMAT SNES_NTSC_RGB16 */
#define SNES_NTSC_IN_FORMAT SNES_NTSC_BGR15
/* The following affect the built-in blitter only; a custom blitter can
handle things however it wants. */
/* Bits per pixel of output. Can be 15, 16, 32, or 24 (same as 32). */
#define SNES_NTSC_OUT_DEPTH 15
/* Type of input pixel values */
#define SNES_NTSC_IN_T unsigned short
/* Each raw pixel input value is passed through this. You might want to mask
the pixel index if you use the high bits as flags, etc. */
#define SNES_NTSC_ADJ_IN( in ) (((in >> 10) & 0x1F) | (in & 0x3E0) | ((in << 10) & 0x7C00))
/* For each pixel, this is the basic operation:
output_color = SNES_NTSC_ADJ_IN( SNES_NTSC_IN_T ) */
#endif

View File

@ -1,439 +0,0 @@
/* snes_ntsc 0.2.2. http://www.slack.net/~ant/ */
/* Common implementation of NTSC filters */
#include <assert.h>
#include <math.h>
/* Copyright (C) 2006 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module 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 Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#define DISABLE_CORRECTION 0
#undef PI
#define PI 3.14159265358979323846f
#ifndef LUMA_CUTOFF
#define LUMA_CUTOFF 0.20
#endif
#ifndef gamma_size
#define gamma_size 1
#endif
#ifndef rgb_bits
#define rgb_bits 8
#endif
#ifndef artifacts_max
#define artifacts_max (artifacts_mid * 1.5f)
#endif
#ifndef fringing_max
#define fringing_max (fringing_mid * 2)
#endif
#ifndef STD_HUE_CONDITION
#define STD_HUE_CONDITION( setup ) 1
#endif
#define ext_decoder_hue (std_decoder_hue + 15)
#define rgb_unit (1 << rgb_bits)
#define rgb_offset (rgb_unit * 2 + 0.5f)
enum { burst_size = snes_ntsc_entry_size / burst_count };
enum { kernel_half = 16 };
enum { kernel_size = kernel_half * 2 + 1 };
typedef struct init_t
{
float to_rgb [burst_count * 6];
float to_float [gamma_size];
float contrast;
float brightness;
float artifacts;
float fringing;
float kernel [rescale_out * kernel_size * 2];
} init_t;
#define ROTATE_IQ( i, q, sin_b, cos_b ) {\
float t;\
t = i * cos_b - q * sin_b;\
q = i * sin_b + q * cos_b;\
i = t;\
}
static void init_filters( init_t* impl, snes_ntsc_setup_t const* setup )
{
#if rescale_out > 1
float kernels [kernel_size * 2];
#else
float* const kernels = impl->kernel;
#endif
/* generate luma (y) filter using sinc kernel */
{
/* sinc with rolloff (dsf) */
float const rolloff = 1 + (float) setup->sharpness * (float) 0.032;
float const maxh = 32;
float const pow_a_n = (float) pow( rolloff, maxh );
float sum;
int i;
/* quadratic mapping to reduce negative (blurring) range */
float to_angle = (float) setup->resolution + 1;
to_angle = PI / maxh * (float) LUMA_CUTOFF * (to_angle * to_angle + 1);
kernels [kernel_size * 3 / 2] = maxh; /* default center value */
for ( i = 0; i < kernel_half * 2 + 1; i++ )
{
int x = i - kernel_half;
float angle = x * to_angle;
/* instability occurs at center point with rolloff very close to 1.0 */
if ( x || pow_a_n > (float) 1.056 || pow_a_n < (float) 0.981 )
{
float rolloff_cos_a = rolloff * (float) cos( angle );
float num = 1 - rolloff_cos_a -
pow_a_n * (float) cos( maxh * angle ) +
pow_a_n * rolloff * (float) cos( (maxh - 1) * angle );
float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff;
float dsf = num / den;
kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - (float) 0.5;
}
}
/* apply blackman window and find sum */
sum = 0;
for ( i = 0; i < kernel_half * 2 + 1; i++ )
{
float x = PI * 2 / (kernel_half * 2) * i;
float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 );
sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman);
}
/* normalize kernel */
sum = 1.0f / sum;
for ( i = 0; i < kernel_half * 2 + 1; i++ )
{
int x = kernel_size * 3 / 2 - kernel_half + i;
kernels [x] *= sum;
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
}
}
/* generate chroma (iq) filter using gaussian kernel */
{
float const cutoff_factor = -0.03125f;
float cutoff = (float) setup->bleed;
int i;
if ( cutoff < 0 )
{
/* keep extreme value accessible only near upper end of scale (1.0) */
cutoff *= cutoff;
cutoff *= cutoff;
cutoff *= cutoff;
cutoff *= -30.0f / 0.65f;
}
cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff;
for ( i = -kernel_half; i <= kernel_half; i++ )
kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff );
/* normalize even and odd phases separately */
for ( i = 0; i < 2; i++ )
{
float sum = 0;
int x;
for ( x = i; x < kernel_size; x += 2 )
sum += kernels [x];
sum = 1.0f / sum;
for ( x = i; x < kernel_size; x += 2 )
{
kernels [x] *= sum;
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
}
}
}
/*
printf( "luma:\n" );
for ( i = kernel_size; i < kernel_size * 2; i++ )
printf( "%f\n", kernels [i] );
printf( "chroma:\n" );
for ( i = 0; i < kernel_size; i++ )
printf( "%f\n", kernels [i] );
*/
/* generate linear rescale kernels */
#if rescale_out > 1
{
float weight = 1.0f;
float* out = impl->kernel;
int n = rescale_out;
do
{
float remain = 0;
int i;
weight -= 1.0f / rescale_in;
for ( i = 0; i < kernel_size * 2; i++ )
{
float cur = kernels [i];
float m = cur * weight;
*out++ = m + remain;
remain = cur - m;
}
}
while ( --n );
}
#endif
}
static float const default_decoder [6] =
{ 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f };
static void init( init_t* impl, snes_ntsc_setup_t const* setup )
{
impl->brightness = (float) setup->brightness * (0.5f * rgb_unit) + rgb_offset;
impl->contrast = (float) setup->contrast * (0.5f * rgb_unit) + rgb_unit;
#ifdef default_palette_contrast
if ( !setup->palette )
impl->contrast *= default_palette_contrast;
#endif
impl->artifacts = (float) setup->artifacts;
if ( impl->artifacts > 0 )
impl->artifacts *= artifacts_max - artifacts_mid;
impl->artifacts = impl->artifacts * artifacts_mid + artifacts_mid;
impl->fringing = (float) setup->fringing;
if ( impl->fringing > 0 )
impl->fringing *= fringing_max - fringing_mid;
impl->fringing = impl->fringing * fringing_mid + fringing_mid;
init_filters( impl, setup );
/* generate gamma table */
if ( gamma_size > 1 )
{
float const to_float = 1.0f / (gamma_size - (gamma_size > 1));
float const gamma = 1.1333f - (float) setup->gamma * 0.5f;
/* match common PC's 2.2 gamma to TV's 2.65 gamma */
int i;
for ( i = 0; i < gamma_size; i++ )
impl->to_float [i] =
(float) pow( i * to_float, gamma ) * impl->contrast + impl->brightness;
}
/* setup decoder matricies */
{
float hue = (float) setup->hue * PI + PI / 180 * ext_decoder_hue;
float sat = (float) setup->saturation + 1;
float const* decoder = setup->decoder_matrix;
if ( !decoder )
{
decoder = default_decoder;
if ( STD_HUE_CONDITION( setup ) )
hue += PI / 180 * (std_decoder_hue - ext_decoder_hue);
}
{
float s = (float) sin( hue ) * sat;
float c = (float) cos( hue ) * sat;
float* out = impl->to_rgb;
int n;
n = burst_count;
do
{
float const* in = decoder;
int n = 3;
do
{
float i = *in++;
float q = *in++;
*out++ = i * c - q * s;
*out++ = i * s + q * c;
}
while ( --n );
if ( burst_count <= 1 )
break;
ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */
}
while ( --n );
}
}
}
/* kernel generation */
#define RGB_TO_YIQ( r, g, b, y, i ) (\
(y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\
(i = (r) * 0.596f - (g) * 0.275f - (b) * 0.321f),\
((r) * 0.212f - (g) * 0.523f + (b) * 0.311f)\
)
#define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\
r = (type) (y + to_rgb [0] * i + to_rgb [1] * q),\
g = (type) (y + to_rgb [2] * i + to_rgb [3] * q),\
(type) (y + to_rgb [4] * i + to_rgb [5] * q)\
)
#define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1)
enum { rgb_kernel_size = burst_size / alignment_count };
enum { rgb_bias = rgb_unit * 2 * snes_ntsc_rgb_builder };
typedef struct pixel_info_t
{
int offset;
float negate;
float kernel [4];
} pixel_info_t;
#if rescale_in > 1
#define PIXEL_OFFSET_( ntsc, scaled ) \
(kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \
(kernel_size * 2 * scaled))
#define PIXEL_OFFSET( ntsc, scaled ) \
PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\
(((scaled) + rescale_out * 10) % rescale_out) ),\
(1.0f - (((ntsc) + 100) & 2))
#else
#define PIXEL_OFFSET( ntsc, scaled ) \
(kernel_size / 2 + (ntsc) - (scaled)),\
(1.0f - (((ntsc) + 100) & 2))
#endif
extern pixel_info_t const snes_ntsc_pixels [alignment_count];
/* Generate pixel at all burst phases and column alignments */
static void gen_kernel( init_t* impl, float y, float i, float q, snes_ntsc_rgb_t* out )
{
/* generate for each scanline burst phase */
float const* to_rgb = impl->to_rgb;
int burst_remain = burst_count;
y -= rgb_offset;
do
{
/* Encode yiq into *two* composite signals (to allow control over artifacting).
Convolve these with kernels which: filter respective components, apply
sharpening, and rescale horizontally. Convert resulting yiq to rgb and pack
into integer. Based on algorithm by NewRisingSun. */
pixel_info_t const* pixel = snes_ntsc_pixels;
int alignment_remain = alignment_count;
do
{
/* negate is -1 when composite starts at odd multiple of 2 */
float const yy = y * impl->fringing * pixel->negate;
float const ic0 = (i + yy) * pixel->kernel [0];
float const qc1 = (q + yy) * pixel->kernel [1];
float const ic2 = (i - yy) * pixel->kernel [2];
float const qc3 = (q - yy) * pixel->kernel [3];
float const factor = impl->artifacts * pixel->negate;
float const ii = i * factor;
float const yc0 = (y + ii) * pixel->kernel [0];
float const yc2 = (y - ii) * pixel->kernel [2];
float const qq = q * factor;
float const yc1 = (y + qq) * pixel->kernel [1];
float const yc3 = (y - qq) * pixel->kernel [3];
float const* k = &impl->kernel [pixel->offset];
int n;
++pixel;
for ( n = rgb_kernel_size; n; --n )
{
float i = k[0]*ic0 + k[2]*ic2;
float q = k[1]*qc1 + k[3]*qc3;
float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 +
k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset;
if ( rescale_out <= 1 )
k--;
else if ( k < &impl->kernel [kernel_size * 2 * (rescale_out - 1)] )
k += kernel_size * 2 - 1;
else
k -= kernel_size * 2 * (rescale_out - 1) + 2;
{
int r, g, b = YIQ_TO_RGB( y, i, q, to_rgb, int, r, g );
*out++ = PACK_RGB( r, g, b ) - rgb_bias;
}
}
}
while ( alignment_count > 1 && --alignment_remain );
if ( burst_count <= 1 )
break;
to_rgb += 6;
ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */
}
while ( --burst_remain );
}
static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out );
#if DISABLE_CORRECTION
#define CORRECT_ERROR( a ) { out [i] += rgb_bias; }
#define DISTRIBUTE_ERROR( a, b, c ) { out [i] += rgb_bias; }
#else
#define CORRECT_ERROR( a ) { out [a] += error; }
#define DISTRIBUTE_ERROR( a, b, c ) {\
snes_ntsc_rgb_t fourth = (error + 2 * snes_ntsc_rgb_builder) >> 2;\
fourth &= (rgb_bias >> 1) - snes_ntsc_rgb_builder;\
fourth -= rgb_bias >> 2;\
out [a] += fourth;\
out [b] += fourth;\
out [c] += fourth;\
out [i] += error - (fourth * 3);\
}
#endif
#define RGB_PALETTE_OUT( rgb, out_ )\
{\
unsigned char* out = (out_);\
snes_ntsc_rgb_t clamped = (rgb);\
SNES_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\
out [0] = (unsigned char) (clamped >> 21);\
out [1] = (unsigned char) (clamped >> 11);\
out [2] = (unsigned char) (clamped >> 1);\
}
/* blitter related */
#ifndef restrict
#if defined (__GNUC__)
#define restrict __restrict__
#elif defined (_MSC_VER) && _MSC_VER > 1300
#define restrict __restrict
#else
/* no support for restricted pointers */
#define restrict
#endif
#endif
#include <limits.h>
#if SNES_NTSC_OUT_DEPTH <= 16
#if USHRT_MAX == 0xFFFF
typedef unsigned short snes_ntsc_out_t;
#else
#error "Need 16-bit int type"
#endif
#else
#if UINT_MAX == 0xFFFFFFFF
typedef unsigned int snes_ntsc_out_t;
#elif ULONG_MAX == 0xFFFFFFFF
typedef unsigned long snes_ntsc_out_t;
#else
#error "Need 32-bit int type"
#endif
#endif

View File

@ -104,9 +104,6 @@ static void set_defaults(void)
g_settings.video.smooth = video_smooth;
g_settings.video.force_aspect = force_aspect;
g_settings.video.aspect_ratio = SNES_ASPECT_RATIO;
#ifdef HAVE_FILTER
g_settings.video.filter = FILTER_NONE;
#endif
g_settings.video.shader_type = SSNES_SHADER_AUTO;
#ifdef HAVE_FREETYPE
@ -301,36 +298,7 @@ static void parse_config_file(void)
#endif
#ifdef HAVE_FILTER
if (config_get_string(conf, "video_filter", &tmp_str))
{
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_STR, FILTER_NTSC_STR);
exit(1);
}
free(tmp_str);
g_settings.video.filter = filter;
}
CONFIG_GET_STRING(video.filter_path, "video_filter");
#endif
#if defined(HAVE_CG) || defined(HAVE_XML)

64
ssnes.c
View File

@ -25,7 +25,7 @@
#include <time.h>
#include "driver.h"
#include "file.h"
#include "hqflt/filters.h"
#include "filters.h"
#include "general.h"
#include "dynamic.h"
#include "record/ffemu.h"
@ -77,23 +77,6 @@ static void set_fast_forward_button(bool new_button_state)
old_button_state = new_button_state;
}
#ifdef HAVE_FILTER
static inline void process_frame (uint16_t * restrict out, const uint16_t * restrict in, unsigned width, unsigned height)
{
int pitch = 1024;
if (height == 448 || height == 478)
pitch = 512;
for (int y = 0; y < height; y++)
{
const uint16_t *src = in + y * pitch;
uint16_t *dst = out + y * width;
memcpy(dst, src, width * sizeof(uint16_t));
}
}
#endif
// libsnes: 0.065
// Format received is 16-bit 0RRRRRGGGGGBBBBB
static void video_frame(const uint16_t *data, unsigned width, unsigned height)
@ -117,44 +100,17 @@ static void video_frame(const uint16_t *data, unsigned width, unsigned height)
const char *msg = msg_queue_pull(g_extern.msg_queue);
#ifdef HAVE_FILTER
uint16_t output_filter[width * height * 4 * 4];
uint16_t output[width * height];
if (g_settings.video.filter != FILTER_NONE)
process_frame(output, data, width, height);
switch (g_settings.video.filter)
unsigned owidth = width;
unsigned oheight = height;
video_filter_size(&owidth, &oheight);
if (g_extern.filter.active)
{
case FILTER_HQ2X:
ProcessHQ2x(output, output_filter);
if (!driver.video->frame(driver.video_data, output_filter, width << 1, height << 1, width << 2, msg))
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, msg))
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, msg))
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, msg))
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, msg))
g_extern.video_active = false;
break;
default:
if (!driver.video->frame(driver.video_data, data, width, height, (height == 448 || height == 478) ? 1024 : 2048, msg))
g_extern.video_active = false;
video_filter_render(g_extern.filter.buffer, g_extern.filter.pitch >> 2, data, (height == 448 || height == 478) ? 512 : 1024, width, height);
if (!driver.video->frame(driver.video_data, g_extern.filter.buffer, owidth, oheight, g_extern.filter.pitch, msg))
g_extern.video_active = false;
}
else if (!driver.video->frame(driver.video_data, data, width, height, (height == 448 || height == 478) ? 1024 : 2048, msg))
g_extern.video_active = false;
#else
if (!driver.video->frame(driver.video_data, data, width, height, (height == 448 || height == 478) ? 1024 : 2048, msg))
g_extern.video_active = false;

View File

@ -52,8 +52,8 @@
# Defines if bilinear filtering is used during second pass (needs render-to-texture).
# video_second_pass_smooth = true
# CPU-based filter. Valid ones are: hq2x, hq4x, grayscale, bleed, ntsc.
# video_filter = ntsc
# CPU-based filter. Path to a bSNES CPU filter (*.filter)
# video_filter =
# Path to a TTF font used for rendering messages. This path must be defined to enable fonts.
# Do note that the _full_ path of the font is necessary!