Advertisement
Guest User

Ultra-fast NES NTSC filtering WIPv2 by Joel Yliluoma

a guest
Nov 29th, 2011
189
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 2.86 KB | None | 0 0
  1.     void PutPixel(unsigned px,unsigned py, unsigned pixel, int offset)
  2.     {
  3.         // The input value is a NES color index (with de-emphasis bits).
  4.         // We need RGB values. To produce a RGB value, we emulate the NTSC circuitry.
  5.         // For most part, this process is described at:
  6.         //    http://wiki.nesdev.com/w/index.php/NTSC_video
  7.         // Incidentally, this code is shorter than a table of 64*8 RGB values.
  8.         static unsigned palette[3][64][512], prev=~0u;
  9.         if(prev==~0u)
  10.             for(int o=0; o<3; ++o)
  11.             for(int b=0; b<512; ++b)
  12.             for(int q=b&~63, a=q; a < q+64; ++a)
  13.             {
  14.                 // Calculate the luma and chroma by emulating the relevant circuits:
  15.                 auto s = "\372\273\32\305\35\311I\330D\357}\13D!}N";
  16.                 int y=0, i=0, q=0;
  17.                 for(int p=0; p<12; ++p) // 12 samples of NTSC signal constitute a color.
  18.                 {
  19.                     // Sample either the previous or the current pixel.
  20.                     int pixel = (p/4+1+o)%3 < 2 ? b : a; // Use pixel=b to disable running pixels.
  21.                     // Decode the color index.
  22.                     int c = pixel%16, l = c<0xE ? pixel/4 & 12 : 4, e=pixel/64;
  23.                     // NES NTSC modulator (square wave between up to four voltage levels):
  24.                     int b = 40 + s[(c > 12*((c+8+p)%12 < 6)) + 2*!(0451326 >> p/2*3 & e) + l];
  25.                     // Ideal TV NTSC demodulator (assuming no color bleeding):
  26.                     y += b;
  27.                     i += b * int(std::cos(M_PI * p / 6) * 5909);
  28.                     q += b * int(std::sin(M_PI * p / 6) * 5909);
  29.                 }
  30.                 // Convert the YIQ color into RGB
  31.                 auto gammafix = [=](float f) { return f <= 0.f ? 0.f : std::pow(f, 2.2f / 1.8f); };
  32.                 auto clamp    = [](int v) { return v>255 ? 255 : v; };
  33.                 palette[o][a%64][b] =
  34.                   + 0x10000*clamp(255 * gammafix(y/1980.f + i* 0.947f/9e6f + q* 0.624f/9e6f))
  35.                   + 0x00100*clamp(255 * gammafix(y/1980.f + i*-0.275f/9e6f + q*-0.636f/9e6f))
  36.                   + 0x00001*clamp(255 * gammafix(y/1980.f + i*-1.109f/9e6f + q* 1.709f/9e6f));
  37.             }
  38.         // Store the RGB color into the frame buffer with subpixel RGB rendering.
  39.         /**********
  40.          * Three possible ways the pixels can be mixed:
  41.          *   prev    current next
  42.          *   --------________--------
  43.          *   0123456789ab0123456789ab <-p (p<4 || p>=8 ? current : prev) = palette[0][prev][current]
  44.          *   89ab0123456789ab01234567 <-p (p>=4        ? current : prev) = palette[1][prev][current]
  45.          *   456789ab0123456789ab0123 <-p (p<8         ? current : prev) = palette[2][prev][current]
  46.          */
  47.         ((u32*) s->pixels) [py*256+px] = palette[offset][prev%64][pixel];
  48.         prev = pixel;
  49.     }
  50.  
  51.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement