News: 11 March 2016 - Forum Rules

Author Topic: Is this possible? (emulator graphics filter idea)  (Read 6744 times)

PresidentLeever

  • Hero Member
  • *****
  • Posts: 899
    • View Profile
    • Mini-Revver
Is this possible? (emulator graphics filter idea)
« on: November 17, 2013, 11:17:13 am »
Sorry if this is too off topic or noobish. I was messing around with filters in Regen the other day, trying to make dither-heavy games look good and wasn't quite happy with any of them as you either get a blurry image or the blending of the dither patterns doesn't happen. So I made these rough sketches below, combining unfiltered and NTSC filtered graphics.

https://plus.google.com/photos/110507989581185950715/albums/5947251753240581329/5947251757700267282?pid=5947251757700267282&oid=110507989581185950715

From left to right (Regen and snes9x screns): no filter, ntsc tv filter by blarrg, rough combo mockup by me, snes screenshot comparison
(Unfortunately the quality isn't great in google photos but if you zoom in you should see the differences. Nevermind the brightness difference, I had to adjust brightness manually since the brighten feature didn't work with filtered screenshot dumps in Regen)

Is this kind of result possible with a general filter, or would it need to be more of a case by case thing with a new setting per game or even per background?

Mini-reviews, retro sound chip tribute, romhacks and general listage at my site: Mini-Revver.

Jorpho

  • Hero Member
  • *****
  • Posts: 5110
  • The cat screams with the voice of a man.
    • View Profile
Re: Is this possible? (emulator graphics filter idea)
« Reply #1 on: November 22, 2013, 09:12:50 am »
Maybe you should just tell us what the difference is, because I for one can't really tell.

If you're talking about applying different filters to the sprites and backgrounds, there will almost certainly be no solution that can be neatly, automatically applied to every game.
This signature is an illusion and is a trap devised by Satan. Go ahead dauntlessly! Make rapid progres!

Starscream

  • Sr. Member
  • ****
  • Posts: 480
    • View Profile
Re: Is this possible? (emulator graphics filter idea)
« Reply #2 on: November 22, 2013, 11:07:14 am »
The screens are too small. But take a look at the stop sign in the second page (Aladdin shots) for example, there you can see the difference.


henke37

  • Hero Member
  • *****
  • Posts: 643
    • View Profile
Re: Is this possible? (emulator graphics filter idea)
« Reply #3 on: November 22, 2013, 03:04:09 pm »
The missing information is what you did in the mockup.

PresidentLeever

  • Hero Member
  • *****
  • Posts: 899
    • View Profile
    • Mini-Revver
Re: Is this possible? (emulator graphics filter idea)
« Reply #4 on: November 22, 2013, 05:20:07 pm »
Oh, I thought most people were familiar with "ctrl" + "+" here. I'll post a better one in a bit.

Here:
http://postimg.org/image/4kip2ihqv/full/
http://postimg.org/image/3kv5f36ip/full/
http://postimg.org/image/xlwomrxw7/full/

If you're talking about applying different filters to the sprites and backgrounds, there will almost certainly be no solution that can be neatly, automatically applied to every game.

I see, that's a shame. I figured it might work since you can turn on and off layers in one of the MD emulators.
« Last Edit: November 22, 2013, 05:30:11 pm by PresidentLeever »
Mini-reviews, retro sound chip tribute, romhacks and general listage at my site: Mini-Revver.

Jorpho

  • Hero Member
  • *****
  • Posts: 5110
  • The cat screams with the voice of a man.
    • View Profile
Re: Is this possible? (emulator graphics filter idea)
« Reply #5 on: November 23, 2013, 01:48:54 am »
Sure, but not every game necessarily uses the same hardware layer to do the same thing.
This signature is an illusion and is a trap devised by Satan. Go ahead dauntlessly! Make rapid progres!

henke37

  • Hero Member
  • *****
  • Posts: 643
    • View Profile
Re: Is this possible? (emulator graphics filter idea)
« Reply #6 on: November 23, 2013, 08:30:00 am »
Some games even use the same background layer for multiple things at once. Or at least different things at different times.

PresidentLeever

  • Hero Member
  • *****
  • Posts: 899
    • View Profile
    • Mini-Revver
Re: Is this possible? (emulator graphics filter idea)
« Reply #7 on: November 23, 2013, 10:43:43 am »
Please tread lightly on my dreams of visual perfection MD style.
Mini-reviews, retro sound chip tribute, romhacks and general listage at my site: Mini-Revver.

Bisqwit

  • Sr. Member
  • ****
  • Posts: 424
  • Polite, but politically incorrect.
    • View Profile
    • http://iki.fi/bisqwit/
Re: Is this possible? (emulator graphics filter idea)
« Reply #8 on: December 02, 2013, 05:57:48 am »
I have actually had some success in the area of undithering algorithms in the past.

Here's the source code of a program I once wrote to undither a picture.
Code: [Select]
#include <gd.h>
#include <stdio.h>
#include <vector>
#include <assert.h>
#include <algorithm>
#include <cmath>

#define G(x) std::pow( (x)/255.0, 2.2)
#define Un(x) 255*std::pow( (x), 1/2.2)

static unsigned avg4pixels(unsigned a,unsigned b,unsigned c,unsigned d)
{
    int r1 = (a>>16)&0xFF, g1 = (a>>8)&0xFF, b1 = (a>>0)&0xFF;
    int r2 = (b>>16)&0xFF, g2 = (b>>8)&0xFF, b2 = (b>>0)&0xFF;
    int r3 = (c>>16)&0xFF, g3 = (c>>8)&0xFF, b3 = (c>>0)&0xFF;
    int r4 = (d>>16)&0xFF, g4 = (d>>8)&0xFF, b4 = (d>>0)&0xFF;
    int rr = Un((G(r1)+G(r2)+G(r3)+G(r4))/4);
    int gg = Un((G(g1)+G(g2)+G(g3)+G(g4))/4);
    int bb = Un((G(b1)+G(b2)+G(b3)+G(b4))/4);
    unsigned res = (rr<<16) + (gg<<8) + (bb);
    //printf("Averages %06X,%06X,%06X,%06X, becomes %06X\n", a,b,c,d,res);
    return res;
}

static bool IsPair(unsigned pix1,unsigned pix2)
{
    int r1 = (pix1 >> 16) & 0xFF, g1 = (pix1 >> 8) & 0xFF, b1 = (pix1) & 0xFF;
    int r2 = (pix2 >> 16) & 0xFF, g2 = (pix2 >> 8) & 0xFF, b2 = (pix2) & 0xFF;
    int rdiff = std::abs(r1-r2);
    int gdiff = std::abs(g1-g2);
    int bdiff = std::abs(b1-b2);
    return (rdiff < 20 && gdiff < 12 && bdiff < 50)
       || (pix1 == 0xFC0000 && pix2 == 0x0034DC)
       || (pix2 == 0xFC0000 && pix1 == 0x0034DC);
}

static const unsigned NotOptimized = 0x7B123456;
static unsigned CheckOptimize(
    unsigned a,unsigned b,
    unsigned c,unsigned d,
    int recursion = 0)
{
    if((IsPair(a,d) && (recursion <= 1 || IsPair(b,c)))
    || (IsPair(b,c) && (recursion <= 1 || IsPair(a,d)))
      )
    {
        if(a != b || a != c || a != d
        || b != c || b != d
        || c != d)
            return avg4pixels(a,b,c,d);
    }
    return NotOptimized;
}

int main(int argc, char** argv)
{
    FILE* fp = fopen(argv[1], "rb");
    gdImagePtr srcim = gdImageCreateFromPng(fp);
    fclose(fp);

    unsigned w = gdImageSX(srcim), h = gdImageSY(srcim);
    gdImagePtr im = gdImageCreateTrueColor(w, h);

    #define GetP(x,y) gdImageGetTrueColorPixel(srcim, x,y)
    #define PSet(x,y,c) gdImageSetPixel(im, x,y,c)

    std::vector<bool> optimized(w*h, false);
    for(unsigned x=0; x<w; ++x)
        for(unsigned y=0; y<h; ++y)
        {
            // Try each of these four patterns
            // * = current pixel
            // . = other pixel which is identical to this one
            // x = two other pixels
            //  Zx    zX   zx   zx
            //  xy    xy   xY   Xy
            if(optimized[y*w+x]) continue;

            for(int xo=-1; xo<=+1; xo+=2)
                for(int yo=-1; yo<=+1; yo+=2)
                    if(int(x)+xo >= 0 && int(x)+xo < int(w)
                    && int(y)+yo >= 0 && int(y)+yo < int(h))
                    {
                        unsigned color = CheckOptimize(
                            GetP(x,   y   ),
                            GetP(x+xo,y   ),
                            GetP(x,   y+yo),
                            GetP(x+xo,y+yo));
                        if(color != NotOptimized)
                        {
                            PSet(x,   y,   color); optimized[(y   )*w+(x   )] = true;
                            PSet(x+xo,y,   color); optimized[(y   )*w+(x+xo)] = true;
                            PSet(x,   y+yo,color); optimized[(y+yo)*w+(x   )] = true;
                            PSet(x+xo,y+yo,color); optimized[(y+yo)*w+(x+xo)] = true;
                            goto done2x2;
                        }
                    }
            PSet(x,y, GetP(x,y));
           done2x2:;
        }

    // Then do the same using 2x2 pixels
    bool changed=true;
    for(int recursion=1; recursion<=1 && changed; ++recursion)
    {
        changed=false;

        gdImageDestroy(srcim);
        srcim = im;
        im = gdImageCreateTrueColor(w,h);

        std::vector<bool> optimized2(w*h, false);
        for(unsigned x=0; x<w; ++x)
            for(unsigned y=0; y<h; ++y)
            {
                if(optimized2[y*w+x]) continue;
                if(x+1 < w && y+1 < h
                && IsPair(GetP(x,y), GetP(x,y+1))
                && IsPair(GetP(x,y), GetP(x+1,y))
                && IsPair(GetP(x,y), GetP(x+1,y+1)))
                {
                    for(int xo=+2; xo>=-2; xo-=4)
                        for(int yo=+2; yo>=-2; yo-=4)
                        if(int(x)+xo >= 0 && int(x)+xo+1 < int(w)
                        && int(y)+yo >= 0 && int(y)+yo+1 < int(h))
                        {
                            if(IsPair(GetP(x+xo,y), GetP(x+xo,  y+1))
                            && IsPair(GetP(x+xo,y), GetP(x+xo+1,y))
                            && IsPair(GetP(x+xo,y), GetP(x+xo+1,y+1))
                            //
                            && IsPair(GetP(x+xo,y+yo), GetP(x+xo,  y+yo+1))
                            && IsPair(GetP(x+xo,y+yo), GetP(x+xo+1,y+yo))
                            && IsPair(GetP(x+xo,y+yo), GetP(x+xo+1,y+yo+1))
                            //
                            && IsPair(GetP(x,y+yo), GetP(x,  y+yo+1))
                            && IsPair(GetP(x,y+yo), GetP(x+1,y+yo))
                            && IsPair(GetP(x,y+yo), GetP(x+1,y+yo+1)))
                            {
                                int x1 = xo<0 ? x+xo : x, x2 = xo<0 ? x+1 : (x+xo+1);
                                int y1 = yo<0 ? y+yo : y, y2 = yo<0 ? y+1 : (y+yo+1);
                                /*
                                printf("x=%d,y=%d,xo=%d,yo=%d,x1=%d,y1=%d,x2=%d,y2=%d, w=%d,h=%d\n",
                                    x,y, xo,yo, x1,y1, x2,y2, w,h);
                                */
                                assert(x1 >= 0);
                                assert(y1 >= 0);
                                assert(x1 < w);
                                assert(y1 < h);
                                unsigned c1 = avg4pixels(GetP(x,y),GetP(x+1,y),GetP(x,y+1),GetP(x+1,y+1));
                                unsigned c2 = avg4pixels(GetP(x+xo,y),GetP(x+xo+1,y),GetP(x+xo,y+1),GetP(x+xo+1,y+1));
                                unsigned c3 = avg4pixels(GetP(x,y+yo),GetP(x+1,y+yo),GetP(x,y+yo+1),GetP(x+1,y+yo+1));
                                unsigned c4 = avg4pixels(GetP(x+xo,y+yo),GetP(x+xo+1,y+yo),GetP(x+xo,y+yo+1),GetP(x+xo+1,y+yo+1));

                                unsigned color = CheckOptimize(c1,c2,c3,c4, recursion);
                                if(color != NotOptimized)
                                {
                                    for(int yp=y1; yp<=y2; ++yp)
                                        for(int xp=x1; xp<=x2; ++xp)
                                        {
                                            PSet(xp,yp, color);
                                            optimized2[yp*w+xp] = true;
                                        }
                                    changed = true;
                                    goto done4x4;
                                }
                            }
                        }
                }
                PSet(x,y, GetP(x,y));
               done4x4:;
            }
    }

    fp = fopen(argv[2], "wb");
    gdImagePng(im, fp);
    fclose(fp); gdImageDestroy(im); gdImageDestroy(srcim);
}

You can read more of the story here: http://bisqwit.iki.fi/story/howto/dither/jy/#FromThereToHere

PresidentLeever

  • Hero Member
  • *****
  • Posts: 899
    • View Profile
    • Mini-Revver
Re: Is this possible? (emulator graphics filter idea)
« Reply #9 on: December 04, 2013, 04:44:04 pm »
Looks very nice. :)
Mini-reviews, retro sound chip tribute, romhacks and general listage at my site: Mini-Revver.

PresidentLeever

  • Hero Member
  • *****
  • Posts: 899
    • View Profile
    • Mini-Revver
Re: Is this possible? (emulator graphics filter idea)
« Reply #10 on: September 19, 2016, 08:43:06 am »
So apparently this kind of filter has been added to Retroarch. Hopefully it will be added to Regen or Fusion soon.




Mini-reviews, retro sound chip tribute, romhacks and general listage at my site: Mini-Revver.

MathUser2929

  • Hero Member
  • *****
  • Posts: 1645
    • View Profile
Re: Is this possible? (emulator graphics filter idea)
« Reply #11 on: September 19, 2016, 09:10:14 am »
Wow, it's like a CRT without the damn scanlines. Still have a clear screen.

Reiska

  • Full Member
  • ***
  • Posts: 144
    • View Profile
Re: Is this possible? (emulator graphics filter idea)
« Reply #12 on: September 21, 2016, 07:21:43 pm »
So apparently this kind of filter has been added to Retroarch. Hopefully it will be added to Regen or Fusion soon.





What's the name of the filter in Retroarch? :O

PresidentLeever

  • Hero Member
  • *****
  • Posts: 899
    • View Profile
    • Mini-Revver
Re: Is this possible? (emulator graphics filter idea)
« Reply #13 on: September 29, 2016, 01:29:51 pm »
I don't know, but here's a thread about it:
http://libretro.com/forums/showthread.php?t=340
Mini-reviews, retro sound chip tribute, romhacks and general listage at my site: Mini-Revver.