The unofficial BSNES pixel shader thread

Anything else related to bsnes goes there.
Locked
grinvader
ZSNES Shake Shake Prinny
Posts: 5632
Joined: Wed Jul 28, 2004 4:15 pm
Location: PAL50, dood !

Post by grinvader »

byuu wrote:
way less intimidating
Please. What self-respecting programmer hasn't memorized up to at least 2^20 in their head? :)

Invaluable for those bit-shift operations ...
PSLLQ ! because why not go for 64 while you're at it...
皆黙って俺について来い!!

Code: Select all

<jmr> bsnes has the most accurate wiki page but it takes forever to load (or something)
Pantheon: Gideon Zhi | CaitSith2 | Nach | kode54
odditude
Official tech support dood
Posts: 2121
Joined: Wed Jan 25, 2006 7:57 am

Post by odditude »

grinvader wrote:
byuu wrote:
way less intimidating
Please. What self-respecting programmer hasn't memorized up to at least 2^20 in their head? :)

Invaluable for those bit-shift operations ...
PSLLQ ! because why not go for 64 while you're at it...
I just remember being really excited when I was in middle school replaying the original Dragon Warrior and suddenly understood why the limits for gold and exp were 65535...
Why yes, my shift key *IS* broken.
creaothceann
Seen it all
Posts: 2302
Joined: Mon Jan 03, 2005 5:04 pm
Location: Germany
Contact:

Post by creaothceann »

grinvader wrote:
creaothceann wrote:2^16
64k

way less intimidating
I wrote it like that at first, but someone might read it as 64 KB.
vSNES | Delphi 10 BPLs
bsnes launcher with recent files list
mudlord
has wat u liek
Posts: 559
Joined: Tue Sep 11, 2007 2:54 pm
Location: Banland.

Post by mudlord »

mudlord I like what you have done with mario and a cube!
Thanks. Though that was a little test to see how the rendering code worked (you can see how I messed up the tex coords in the sample though :lol:) . And it now works fine. Thanks again VG. 8)
You could use a buffer of 2^16 items to store the final 24-bit values.
Hmmmz, true. Although, it works fine enough though at the moment (though I have a C2D 4500, so speed isn't really a problem. My only concern is the pressure my emulator will put on the video card in older PCs, since it uses dynamic plasma effects, wave/water effects and other things that involve changing textures every single frame. And it all does this without shaders. But we will see when I release it.)
mudlord
has wat u liek
Posts: 559
Joined: Tue Sep 11, 2007 2:54 pm
Location: Banland.

Post by mudlord »

I upgraded ubuntu to 8.04 and tried running my bsnes opengl 2.0 driver with visual effects set to normal and extra, and it did not work, It just showed me a white screen!
Dude, there is a bug in your code. I fixed it:

Code: Select all

 glCreateProgram = (PFNGLCREATEPROGRAMPROC)wglGetProcAddress("glCreateProgram");
    glUseProgram = (PFNGLUSEPROGRAMPROC)wglGetProcAddress("glUseProgram");
    glCreateShader = (PFNGLCREATESHADERPROC)wglGetProcAddress("glCreateShader");
    glShaderSource = (PFNGLSHADERSOURCEPROC)wglGetProcAddress("glShaderSource");
    glCompileShader = (PFNGLCOMPILESHADERPROC)wglGetProcAddress("glCompileShader");
    glAttachShader = (PFNGLATTACHSHADERPROC)wglGetProcAddress("glAttachShader");
    glLinkProgram = (PFNGLLINKPROGRAMPROC)wglGetProcAddress("glLinkProgram");
    glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)wglGetProcAddress("glGetUniformLocation");
    glUniform1i = (PFNGLUNIFORM1IPROC)wglGetProcAddress("glUniform1i");

    // Create our fragment shader...
    fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);

    FILE *fp = fopen("shader.frag", "rb"); 
    fseek(fp, 0, SEEK_END); 
    int size = ftell(fp); 
    fseek(fp, 0, SEEK_SET); 
    char *buffer = new char[size + 1]; 
    fread(buffer, 1, size, fp); 
    buffer[size] = 0; 
    fclose(fp); 
    const char *fbuffer = buffer; 

    glShaderSource(fragmentshader, 1, &fbuffer, 0); 
    glCompileShader(fragmentshader); 
    delete[] buffer;

    // Create a program object and attach our compiled fragment shader to it...
    program = glCreateProgram();
    glAttachShader(program, fragmentshader);

    // Link the program object...
    glLinkProgram(program);

    // Locate some parameters by name so we can set them later...
    glGetUniformLocation(program, "texture");
The problem was gltexture = glGetUniformLocation(program, "texture");

Thats the fixed version. Works for me in my MuNES. :P Thanks again for porting my pixel shaders!

Image
krom
Rookie
Posts: 13
Joined: Sat Sep 29, 2007 4:08 am
Contact:

Bug in my bsnes shader code

Post by krom »

Dude, there is a bug in your code. I fixed it
Cheers man, I have updated my sources =D
Works for me in my MuNES. Thanks again for porting my pixel shaders!
No probs!
mudlord
has wat u liek
Posts: 559
Joined: Tue Sep 11, 2007 2:54 pm
Location: Banland.

Post by mudlord »

krom, found some more issues with your code using glIntercept. I will post some patched code ASAP. IIRC, ATI cards need vertex shaders, as well as fragment shaders, for some retarded reason. As such, I will be posting some code that should add vertex shader support, too.
mudlord
has wat u liek
Posts: 559
Joined: Tue Sep 11, 2007 2:54 pm
Location: Banland.

Post by mudlord »

Code: Select all

PFNGLCREATEPROGRAMOBJECTARBPROC  glCreateProgramObjectARB  = NULL;
PFNGLDELETEOBJECTARBPROC         glDeleteObjectARB         = NULL;
PFNGLUSEPROGRAMOBJECTARBPROC     glUseProgramObjectARB     = NULL;
PFNGLCREATESHADEROBJECTARBPROC   glCreateShaderObjectARB   = NULL;
PFNGLSHADERSOURCEARBPROC         glShaderSourceARB         = NULL;
PFNGLCOMPILESHADERARBPROC        glCompileShaderARB        = NULL;
PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB = NULL;
PFNGLATTACHOBJECTARBPROC         glAttachObjectARB         = NULL;
PFNGLGETINFOLOGARBPROC           glGetInfoLogARB           = NULL;
PFNGLLINKPROGRAMARBPROC          glLinkProgramARB          = NULL;
PFNGLGETUNIFORMLOCATIONARBPROC   glGetUniformLocationARB   = NULL;
PFNGLUNIFORM4FARBPROC            glUniform4fARB            = NULL;
PFNGLUNIFORM1IARBPROC            glUniform1iARB            = NULL;

void initShader(char *filename, char* filename2) {
    glCreateProgramObjectARB  = (PFNGLCREATEPROGRAMOBJECTARBPROC)wglGetProcAddress("glCreateProgramObjectARB");
    glDeleteObjectARB         = (PFNGLDELETEOBJECTARBPROC)wglGetProcAddress("glDeleteObjectARB");
    glUseProgramObjectARB     = (PFNGLUSEPROGRAMOBJECTARBPROC)wglGetProcAddress("glUseProgramObjectARB");
    glCreateShaderObjectARB   = (PFNGLCREATESHADEROBJECTARBPROC)wglGetProcAddress("glCreateShaderObjectARB");
    glShaderSourceARB         = (PFNGLSHADERSOURCEARBPROC)wglGetProcAddress("glShaderSourceARB");
    glCompileShaderARB        = (PFNGLCOMPILESHADERARBPROC)wglGetProcAddress("glCompileShaderARB");
    glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC)wglGetProcAddress("glGetObjectParameterivARB");
    glAttachObjectARB         = (PFNGLATTACHOBJECTARBPROC)wglGetProcAddress("glAttachObjectARB");
    glGetInfoLogARB           = (PFNGLGETINFOLOGARBPROC)wglGetProcAddress("glGetInfoLogARB");
    glLinkProgramARB          = (PFNGLLINKPROGRAMARBPROC)wglGetProcAddress("glLinkProgramARB");
    glGetUniformLocationARB   = (PFNGLGETUNIFORMLOCATIONARBPROC)wglGetProcAddress("glGetUniformLocationARB");
    glUniform4fARB            = (PFNGLUNIFORM4FARBPROC)wglGetProcAddress("glUniform4fARB");
	glUniform1iARB            = (PFNGLUNIFORM1IARBPROC)wglGetProcAddress("glUniform1iARB");
    // Create our fragment shader...
    fragmentshader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER);
	vertexshader = glCreateShaderObjectARB(GL_VERTEX_SHADER);
	//for the frag shader
    FILE *fp = fopen(filename, "rb"); 
    fseek(fp, 0, SEEK_END); 
    int size = ftell(fp); 
    fseek(fp, 0, SEEK_SET); 
    char *buffer = new char[size + 1]; 
    fread(buffer, 1, size, fp); 
    buffer[size] = 0; 
    fclose(fp); 
    const char *fbuffer = buffer; 
    glShaderSourceARB(fragmentshader, 1, &fbuffer, 0); 
    glCompileShaderARB(fragmentshader); 
    delete[] buffer;

	//for the vertex shader
    FILE *fp2 = fopen(filename2, "rb"); 
    fseek(fp2, 0, SEEK_END); 
    int size2 = ftell(fp2); 
    fseek(fp2, 0, SEEK_SET); 
    char *buffer2 = new char[size2 + 1]; 
    fread(buffer2, 1, size2, fp2); 
    buffer2[size2] = 0; 
    fclose(fp2); 
    const char *vbuffer = buffer2; 
    glShaderSourceARB(vertexshader, 1, &vbuffer, 0); 
    glCompileShaderARB(vertexshader); 
    delete[] buffer2;

    // Create a program object and attach our compiled fragment shader to it...
    program = glCreateProgramObjectARB();
    glAttachObjectARB(program, fragmentshader);
    glAttachObjectARB(program, vertexshader);
    // Link the program object...
    glLinkProgramARB(program);
    // Locate some parameters by name so we can set them later...
    glGetUniformLocationARB(program, "texture");
}
And when you render.....

Code: Select all

if (useShaders == 1)
	glUseProgramObjectARB(program);

        *render textured quad here*
	
	if (useShaders == 1)
	glUseProgramObjectARB(NULL);
There.
DOLLS (J) [!]
ZNES Developer
Posts: 215
Joined: Mon Aug 02, 2004 11:22 pm

Post by DOLLS (J) [!] »

During my previous efforts with cubic kernels I realised that the methods were probably overkill for the kind of images they would be subjected to, rather, I opted to construct a quadratic kernel with a small radius, one that requires 4 texture fetches, making it readily PS v2.0 compliant. It was constructed with sharpness in mind, so everyone that enjoys the pixelated look, but can't cope with the artifacts of non-uniform box filtering, rejoice.

At the time the shader ignores any extra information provided by the pseudo-hires modes (it only maps to a 256x224 or 256x239 texture), figures for the highest resolution modes in NTSC and PAL are welcome, so that I may implement this later.

Pixel shader: Quadratic interpolation.
v0.1 - Release
v0.11 - Fixed resolution detection.

NOT tested with any hardware besides mine.

Usage:
Patch bsnes and copy/paste the following code into a "shader.fx" file inside the main folder.
Launch bsnes and make sure to check "Point" and "None" in the "Filter" menu.
Test and provide feedback.

Examples:
1x with NTSC aspect ratio compensation:
Image

3x with NTSC aspect ratio compensation:
Image

Source:

Code: Select all

/* Quadratic Resampler v0.11
 * By DOLLS
 * Do not distribute a modified version without permission. 
 */

texture tex1, tex2;
float2 rcpres;
sampler s0 = sampler_state {
	texture = <tex1>;
	AddressU = mirror;
	AddressV = mirror;
};

sampler s1 = sampler_state {
	texture = <tex2>;
	AddressU = mirror;
	AddressV = mirror;
};

int2 res;

float4 Normalize(in float2 coord : TEXCOORD0): COLOR0
{		
	res = int2(256, (frac(1 / (224 * rcpres.y)) < 0.05)? 224 : 239);
	float2 loc = coord * float2(rcpres.y * res.y / (rcpres.x * res.x), 1.0) / (res.y * rcpres.y);
	return tex2D(s0, loc);		
}

float pow2(float x)
{
   return x * x;
}

float getWeight(float x)
{	
	if (x == 0.0) return 1.0;
	else if (x < 0.5) return 1 - 2 * pow2(x);
	else if (x < 1.0) return 2 * pow2(1 - x);
	else return 0.0;	
}

float4 Resample(in float2 coord : TEXCOORD0) : COLOR0
{	
	res = int2(256, (frac(1 / (224 * rcpres.y)) < 0.05)? 224 : 239);
	float2 pos = coord * res - 0.5;
	float2 tex = (floor(pos) + 0.5) * rcpres;
	float2 next_tex = tex + rcpres;
		
	float2 delta = frac(pos);
	float2 w0 = float2(getWeight(delta.x), getWeight(delta.y));
	float2 w1 = float2(getWeight(1 - delta.x), getWeight(1 - delta.y));
	
	float4 value = w0.x * w0.y * tex2D(s1, tex);
	value += w1.x * w0.y * tex2D(s1, float2(next_tex.x, tex.y));
	value += w0.x * w1.y * tex2D(s1, float2(tex.x, next_tex.y));
	value += w1.x * w1.y * tex2D(s1, next_tex);
	return value;		
}

Technique T0
{		
	pass p0 {		
		PixelShader = compile ps_2_0 Normalize();
	}		
	pass p1 {
		PixelShader = compile ps_2_0 Resample();
	}		
}
mudlord
has wat u liek
Posts: 559
Joined: Tue Sep 11, 2007 2:54 pm
Location: Banland.

Post by mudlord »

Not a bad shader! I am considering adding this to the shader pack, if you don't mind :D .

Any chance of a Lanczos shader? :P
DOLLS (J) [!]
ZNES Developer
Posts: 215
Joined: Mon Aug 02, 2004 11:22 pm

Post by DOLLS (J) [!] »

mudlord: Sure, go ahead!

New shaders:
Cubic spline & Lanczos2 based resamplers, normal & gamma corrected, gamma corrected variation of the Quadratic resampler added as well.

Lanczos3 (the common one) was avoided as it introduces unnecessary ringing artifacts, it's better suited for captured media (photo, video).

If your display operates in sRGB color space (gamma 2.2 calibrated), you might want to check out the gamma corrected variations of the shaders ("_sRGB" appended in the filename, remove that part).
PS v2.0a required.

Download link:
http://www.megaupload.com/?d=MDEU3IYZ
(Sorry, my FTP is currently offline)
DOLLS wrote:At the time the shader ignores any extra information provided by the pseudo-hires modes (it only maps to a 256x224 or 256x239 texture), figures for the highest resolution modes in NTSC and PAL are welcome, so that I may implement this later.
I'm still requesting this information.
mudlord
has wat u liek
Posts: 559
Joined: Tue Sep 11, 2007 2:54 pm
Location: Banland.

Post by mudlord »

mudlord: Sure, go ahead!
Okay.

I will update the pack when I update my site. Which is when I am in the mood to.
krom
Rookie
Posts: 13
Joined: Sat Sep 29, 2007 4:08 am
Contact:

Cheers mudlord

Post by krom »

krom, found some more issues with your code using glIntercept. I will post some patched code ASAP. IIRC, ATI cards need vertex shaders, as well as fragment shaders, for some retarded reason. As such, I will be posting some code that should add vertex shader support, too.
Sorry for the late reply mudlord,
Thanks a lot for the new code, I have updated my sources and I am very appreciative of your help =D

btw how is the nes emu going?
mudlord
has wat u liek
Posts: 559
Joined: Tue Sep 11, 2007 2:54 pm
Location: Banland.

Post by mudlord »

Sorry for the late reply mudlord,
Thanks a lot for the new code, I have updated my sources and I am very appreciative of your help =D

btw how is the nes emu going?
No probs!

And its going excellent. I need to replace SDL as a sound server, though I have very little experience with DirectSound or WinMM. If anyone can help, I would be so grateful.

All I need is some code that
* has a init function that sets the samplerate
* a closing function that is a void()
* a writing function that has a parameter, that sets the amount of samples processed, as well as a parameter that contains the raw audio data.

Currently my code is based of Sound_Queue by blargg, so that should give ideas in how to do the WinMM/DSound sound server. (I know byuu was wanting to do something for me...maybe this can be it).
byuu

Post by byuu »

All of that is in src/lib/ruby/audio/directsound.cpp :D
Only 5kb in size.

Init:

Code: Select all

    DirectSoundCreate(0, &ds, 0);
    ds->SetCooperativeLevel((HWND)settings.handle, DSSCL_PRIORITY);

    memset(&dsbd, 0, sizeof(dsbd));
    dsbd.dwSize        = sizeof(dsbd);
    dsbd.dwFlags       = DSBCAPS_PRIMARYBUFFER;
    dsbd.dwBufferBytes = 0;
    dsbd.lpwfxFormat   = 0;
    ds->CreateSoundBuffer(&dsbd, &dsb_p, 0);

    memset(&wfx, 0, sizeof(wfx));
    wfx.wFormatTag      = WAVE_FORMAT_PCM;
    wfx.nChannels       = 2;
    wfx.nSamplesPerSec  = settings.frequency;
    wfx.wBitsPerSample  = 16;
    wfx.nBlockAlign     = wfx.wBitsPerSample / 8 * wfx.nChannels;
    wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
    dsb_p->SetFormat(&wfx);

    memset(&dsbd, 0, sizeof(dsbd));
    dsbd.dwSize          = sizeof(dsbd);
    dsbd.dwFlags         = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLFREQUENCY |
                           DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCSOFTWARE;
    dsbd.dwBufferBytes   = data.ring_size * 3;
    dsbd.guid3DAlgorithm = GUID_NULL;
    dsbd.lpwfxFormat     = &wfx;
    ds->CreateSoundBuffer(&dsbd, &dsb_b, 0);
    dsb_b->SetFrequency(settings.frequency);
    dsb_b->SetCurrentPosition(0);
Term:

Code: Select all

    if(dsb_b) { dsb_b->Stop(); dsb_b->Release(); dsb_b = 0; }
    if(dsb_p) { dsb_p->Stop(); dsb_p->Release(); dsb_p = 0; }
    if(ds) { ds->Release(); ds = 0; }
Write:

Code: Select all

    data.buffer[data.buffer_pos++] = (l_sample << 0) + (r_sample << 16);
    if(data.buffer_pos < settings.frequency / 40) return;

  DWORD ring_pos, pos, size;
    for(;;) {
      dsb_b->GetCurrentPosition(&pos, 0);
      ring_pos = pos / data.ring_size;
      if(settings.synchronize == false || ring_pos != data.ring_pos) break;
      Sleep(1);
    }

    data.ring_pos = ring_pos;
  void *output;
    if(dsb_b->Lock(((data.ring_pos + 2) % 3) * data.ring_size, data.ring_size,
      &output, &size, 0, 0, 0) == DS_OK) {
      memcpy(output, data.buffer, data.ring_size);
      dsb_b->Unlock(output, size, 0, 0);
    }

    data.buffer_pos = 0;
Link with -ldsound or dsound.lib.

I'll be happy to go over any section that is unclear in detail, if you like.

You're free to use all of src/lib directly as public domain, as well.
mudlord
has wat u liek
Posts: 559
Joined: Tue Sep 11, 2007 2:54 pm
Location: Banland.

Post by mudlord »

Strange, tried out the code, failed to work. :(

Not a single bit of sound, apart from a close to inaudible buzz. :(

Here's the main callback function for sound if you are interested.....

Code: Select all

void NESCore_Callback_OutputSample(int nSamples, byte *channel1, byte *channel2,
    byte *channel3, byte *channel4, byte *channel5)
{
	short temp [1024];
	int i;
	for ( i = 0; i < nSamples; i++ )
    temp [i] = (channel1 [i] + channel2 [i] + channel3 [i] + channel4 [i] + channel5 [i]) * 32;

   // sync_audio_write( temp, nSamples );
	sample((int16_t)temp);


}
I changed the "sample" function of your class, to make "temp" write to it, unfortunately it done nothing...

sync_audio_write() was the SDL related function that I was talking about before...
mudlord
has wat u liek
Posts: 559
Joined: Tue Sep 11, 2007 2:54 pm
Location: Banland.

Post by mudlord »

Hheehehe, found a workaround to the problem.

Instead of adding DirectSound, I completely regutted SDL.

Everything not relating to threads, mutexes, or raw DirectSound audio has been completely stripped. Result? Managed to shrink the entire library from a mammoth ~150KB to a petite 24.5KB. Which is perfect for what I am using it for. :lol:
byuu

Post by byuu »

mudlord wrote:Hheehehe, found a workaround to the problem.

Instead of adding DirectSound, I completely regutted SDL.

Everything not relating to threads, mutexes, or raw DirectSound audio has been completely stripped. Result? Managed to shrink the entire library from a mammoth ~150KB to a petite 24.5KB. Which is perfect for what I am using it for. :lol:
Ah, I believe someone else did that with one of the driver classes ... I want to say it was input related, but i can't be sure. You guys are truly brave to gut such a massive program like that, heh.

Anyway, sounds neat! If you change your mind, let me know. I'd need you to send me your source code, though, so I can get it working on my side. That, or perhaps I could make the DSound lib into its own app with nothing else in the way that just plays a quick WAV file or something using an API similar to yours.

I dare say raw DSound is a bit better (love the ability to query the play cursor position), but it hinders portability, so your single API solution is probably best.
mudlord
has wat u liek
Posts: 559
Joined: Tue Sep 11, 2007 2:54 pm
Location: Banland.

Post by mudlord »

That, or perhaps I could make the DSound lib into its own app with nothing else in the way that just plays a quick WAV file or something using an API similar to yours.
That would be so cool :) Even a sample showing a sine wave will be enough, since we are dealing with raw audio data.

I admit, I am kinda very ashamed to show you my GUI/IO source code. :( It is super messy, with some global variables, as well as using the Windows message pump to process core events, instead of using a seperate thread (OpenGL is extremely picky on which threads rendering contexts are made), though I do plan on fixing that.

Though, the emu does run extremely fast on a 1.3 Celeron M. The render code is quite weird too, since I do plan on adding some extra rendering features at a later date....
mudlord
has wat u liek
Posts: 559
Joined: Tue Sep 11, 2007 2:54 pm
Location: Banland.

Post by mudlord »

Sent the code.

Beware again, I can't stress enough how ugly it may look. Sorry 'bout that. I will fix it when I solve the OpenGL thread issues.
byuu

Post by byuu »

mudlord wrote:That would be so cool :) Even a sample showing a sine wave will be enough, since we are dealing with raw audio data.
Here's one that outputs static at 22khz / 16-bit stereo. You can easily change things via audio.settings.frequency, audio.settings.synchronize, etc before-hand.

To set it up, you call audio.init(), write samples with audio.sample(left, right), and finish with audio.term().

Compile with kernel32.lib, user32.lib, dsound.lib and uuid.lib.

Binary and source included. My example has synchronization on, meaning it will put the process to sleep when too much data is in the sound buffer. It's a purely sync-to-audio setup, the same as with bsnes. Hopefully that's appropriate for MuNES, because I don't know how to do it any other way.

http://www.geocities.com/byuu64/directsound.zip
It is super messy, with some global variables, as well as using the Windows message pump to process core events, instead of using a seperate thread
Eh, it looks pretty good to me. Not 100% abstracted, but so long as it's Windows-only, that's not really a problem.

I do wish you'd drop VC6, though. That compiler is evil :P
mudlord
has wat u liek
Posts: 559
Joined: Tue Sep 11, 2007 2:54 pm
Location: Banland.

Post by mudlord »

Here's one that outputs static at 22khz / 16-bit stereo. You can easily change things via audio.settings.frequency, audio.settings.synchronize, etc before-hand.

To set it up, you call audio.init(), write samples with audio.sample(left, right), and finish with audio.term().

Compile with kernel32.lib, user32.lib, dsound.lib and uuid.lib.
Thank you! Much appreciated!

MuNES without SDL.dll as dependancy:
http://vba-m.ngemu.com/munes_vc6.rar
Eh, it looks pretty good to me. Not 100% abstracted, but so long as it's Windows-only, that's not really a problem.

I do wish you'd drop VC6, though. That compiler is evil :P
Thanks, I honestly think though some parts can still be improved. Its quite hackish. Though, it does the job :/

I agree though about VC6, but I want to be assured that it runs with as little dependancies as possible. MSVCR71.DLL aint a option, if thats what your implying. I am trying my hardest to keep around 64KB and no over...or in the event of that, 96KB.

*curses VC6 over its DWORD_PTR support*
tetsuo55
Regular
Posts: 307
Joined: Sat Mar 04, 2006 3:17 pm

Post by tetsuo55 »

Hi guys

Is anyone willing/able to turn this into a shader filter?

NTSC tv phosphor simulation filter

Image is scaled(without filters) to 4800*2700

In each pixel color data is deleted so only 1 color remains

The deletion works as follows:
(width*height)
10*45 black pixels(all color data is dropped)
10*45 red pixles (blue and green are dropped)
10*45 black pixels(all color data is dropped)
10*45 green pixels(Red and blue are dropped)
10*45 black pixels(all color data is dropped)
10*45 blue pixels(red and green are dropped)

Each 10*45 block is averaged into a single color
The 6 10*45 blocks are mixed into a new single color

The single color 60*45 block is scaled down to 1 pixel

The result is a single 800*600 image which can then be displayed on screen

This image will be an accurate representation of a basic NTSC tv's phosphor map. However due to the lack of whiter than white's the image will look overly dark.

Without a working filter there is no way to see how much gamma correction is needed to fix this.

I bet this whole calculation could be simplified into a single line of code by someone good with math
Verdauga Greeneyes
Regular
Posts: 347
Joined: Tue Mar 07, 2006 10:32 am
Location: The Netherlands

Post by Verdauga Greeneyes »

Because of the way shaders work, we cannot resize the input to a 4800*2700 image before processing (at least in the current implementation). We get a 1024x1024 image from bsnes of which only a part is in use (i.e. 256x224 for unfiltered low-res NTSC), and we output to whatever scale factor you have bsnes set to.

Anyway, that doesn't mean your idea won't work just fine, just not in the way you presented it :)
tetsuo55
Regular
Posts: 307
Joined: Sat Mar 04, 2006 3:17 pm

Post by tetsuo55 »

okay.

i think the entire thing, apart from the stretch to 800x600 part can be done with math alone.
Locked