diff -Naur CommonFilters190_ref/CommonFilters.py CommonFilters190_retro/CommonFilters.py
--- CommonFilters190_ref/CommonFilters.py	2015-01-25 21:58:07.509490000 +0200
+++ CommonFilters190_retro/CommonFilters.py	2015-01-28 00:28:22.047951000 +0200
@@ -39,7 +39,7 @@
 from VolumetricLightingCompositor import VolumetricLightingCompositor
 from VolumetricLighting import VolumetricLighting
 
-from MiscFilters import ViewGlow, ColorInversion, GammaAdjust, Tint, CartoonInkClassic, AntialiasFXAA, Vignetting
+from MiscFilters import ViewGlow, ColorInversion, GammaAdjust, Tint, CartoonInkClassic, AntialiasFXAA, Vignetting, Pixelization, Posterization
 
 import FilterUtils
 
@@ -137,6 +137,8 @@
         self.scanlines          = None
         self.tint               = None
         self.vignetting         = None
+        self.pixelization       = None
+        self.posterization      = None
 
 
     # Here we create the filter instances using their default stageName and sort.
@@ -365,7 +367,7 @@
 
 
     @oldSetFilter
-    def setScanlines(self, strength=0.5, lineThickness=1, dynamicFlip=False, top=True, bandStrength=0.1, bandSpeed=0.75, bandSize=1.0):
+    def setScanlines(self, strength=0.5, lineThickness=1, dynamicFlip=False, top=True, bandStrength=0.1, bandSpeed=0.75, bandSize=1.0, enableTint=False):
         if self.scanlines is None:
             self.scanlines = Scanlines()
             self.addFilterInstance(self.scanlines)
@@ -377,6 +379,7 @@
         self.scanlines.bandStrength   = bandStrength
         self.scanlines.bandSpeed      = bandSpeed
         self.scanlines.bandSize       = bandSize
+        self.scanlines.enableTint     = enableTint
 
     @oldDelFilter
     def delScanlines(self):
@@ -591,3 +594,31 @@
             self.removeFilterInstance(self.localReflection)
             self.localReflection = None
 
+    @oldSetFilter
+    def setPixelization(self, sizex=4, sizey=4):
+        if self.pixelization is None:
+            self.pixelization = Pixelization()
+            self.addFilterInstance(self.pixelization)
+        self.pixelization.sizex = sizex
+        self.pixelization.sizey = sizey
+
+    @oldDelFilter
+    def delPixelization(self):
+        if self.pixelization is not None:
+            self.removeFilterInstance(self.pixelization)
+            self.pixelization = None
+
+    @oldSetFilter
+    def setPosterization(self, quantization=8, gamma=2.2):
+        if self.posterization is None:
+            self.posterization = Posterization()
+            self.addFilterInstance(self.posterization)
+        self.posterization.quantization = quantization
+        self.posterization.gamma        = gamma
+
+    @oldDelFilter
+    def delPosterization(self):
+        if self.posterization is not None:
+            self.removeFilterInstance(self.posterization)
+            self.posterization = None
+
diff -Naur CommonFilters190_ref/MiscFilters.py CommonFilters190_retro/MiscFilters.py
--- CommonFilters190_ref/MiscFilters.py	2015-01-17 14:01:40.628466000 +0200
+++ CommonFilters190_retro/MiscFilters.py	2015-01-28 00:29:26.155058000 +0200
@@ -138,6 +138,7 @@
         super(Tint, self).onReset()  # reset inherited properties
         self.sort  = 90  # late within the pipeline stage
         self.stageName = "Postprocess"
+
         self.color = (0.5,0.5,0.5,1)  # default is darken by 50%
         self.strength = 1.0
         self.mode  = "multiply"  # compile-time parameter
@@ -240,11 +241,14 @@
         self.stageName = "DisplayDevice"
         self.sort = 90
 
+        self.gamma = 2.2
+
     def onAttachPipeline(self):
         # This filter needs no textures, custom inputs, aux bits, or internal stages,
-        # but this method is abstract in the Filter base class. Thus, we just provide
-        # a blank implementation to fulfill the interface and acknowledge that
-        # this filter doesn't need to do anything here.
+        # but this method is abstract in the Filter base class, because almost all filters do.
+        #
+        # Thus, we just provide a blank implementation to fulfill the interface and acknowledge
+        # the very exceptional case that this filter doesn't need to do anything here.
         #
         pass
 
@@ -537,3 +541,161 @@
         if self.finalQuad is not None:
             self.finalQuad.setShaderInput( self.getMangledName("vignetting_strength"), value )
 
+
+PIXELIZATION_BODY="""const float dx = %(k_params)s.x * %(texpix_txcolor)s.x;
+const float dy = %(k_params)s.y * %(texpix_txcolor)s.y;
+
+float2 coord = float2( dx*floor(%(texcoord_txcolor)s.x/dx), dy*floor(%(texcoord_txcolor)s.y/dy) );
+
+pixcolor = tex2D( %(k_txcolor)s, coord );
+"""
+
+class Pixelization(Filter):
+    """Filter that pixelates (subsamples) the image, producing a mosaic.
+
+    Introduced in Panda 1.9.0.
+
+    """
+    def __init__(self, **kwargs):
+        super(Pixelization, self).__init__(**kwargs)
+
+    def onReset(self):
+        super(Pixelization, self).onReset()  # reset inherited properties
+
+        # This filter needs to read its input texture at an arbitrary location,
+        # and it overwrites pixcolor, so it is not mergeable, and must come first
+        # in the stage it is placed in.
+        #
+        self.sort = 0
+        self.stageName   = "DisplayDevice"
+        self.isMergeable = False
+
+        self.sizex = 4
+        self.sizey = 4
+
+    def onAttachPipeline(self):
+        self.registerInputTexture(texName="color")
+        self.registerCustomInput(inputType="float4", inputName="k_params")
+
+    def onSynthesizeCompositor(self):
+        txcolor = self.getTextureInfo("color")
+        code = PIXELIZATION_BODY % { "k_params"         : self.getMangledName("k_params"),
+                                     "k_txcolor"        : txcolor.varname,
+                                     "texcoord_txcolor" : txcolor.texcoord,
+                                     "texpix_txcolor"   : txcolor.texpix }
+        return ("pixelization", code, "// pixelization (mosaic) filter\n")
+
+    # Combine sizex and sizey into one shader input.
+    def _computeParams(self):
+        return Vec4(self._sizex, self._sizey, 0.0, 0.0)
+
+    @property
+    def sizex(self):
+        """Size of pixelization in the x direction.
+
+        Integer, >= 1. Default 4.
+
+        """
+        return self._sizex
+    @sizex.setter
+    def sizex(self, value):
+        self._sizex = int(value)
+        if self.finalQuad is not None:
+            self.finalQuad.setShaderInput( self.getMangledName("params"), self._computeParams() )
+
+    @property
+    def sizey(self):
+        """Size of pixelization in the y direction.
+
+        Integer, >= 1. Default 4.
+
+        """
+        return self._sizey
+    @sizey.setter
+    def sizey(self, value):
+        self._sizey = int(value)
+        if self.finalQuad is not None:
+            self.finalQuad.setShaderInput( self.getMangledName("params"), self._computeParams() )
+
+
+POSTERIZATION_BODY="""float nColors = %(k_params)s.x;
+float gamma = %(k_params)s.y;
+float invgamma = %(k_params)s.z;
+
+float3 c = pixcolor.rgb;
+c = pow(c, gamma);
+c *= nColors;
+c = floor(c);
+c /= nColors;
+pixcolor.rgb = pow(c, invgamma);
+"""
+
+class Posterization(Filter):
+    """Filter that posterizes the image (reduces colors).
+
+    Introduced in Panda 1.9.0.
+
+    """
+    def __init__(self, **kwargs):
+        super(Posterization, self).__init__(**kwargs)
+
+    def onReset(self):
+        super(Posterization, self).onReset()  # reset inherited properties
+
+        self.sort = 70
+        self.stageName   = "DisplayDevice"
+        self.isMergeable = True
+
+        self.quantization = 8
+        self.gamma        = 2.2
+
+    def onAttachPipeline(self):
+        self.registerCustomInput(inputType="float4",  inputName="k_params")
+
+    def onSynthesizeCompositor(self):
+        code = POSTERIZATION_BODY % { "k_params" : self.getMangledName("k_params") }
+        return ("posterization", code, "// posterization (color reduction) filter\n")
+
+    # Combine quantization and gamma into one shader input.
+    def _computeParams(self):
+        # We save a division in the fshader by precomputing the inverse of gamma.
+        return Vec4(self._quantization, self._gamma, 1.0/self.gamma, 0.0)
+
+    @property
+    def quantization(self):
+        """Number of intensity levels preserved in posterization.
+
+        The same value is used in all color components (R,G,B) independently.
+
+        Integer, >= 1. Default 8.
+
+        """
+        return self._quantization
+    @quantization.setter
+    def quantization(self, value):
+        self._quantization = int(value)
+        if self.finalQuad is not None:
+            self.finalQuad.setShaderInput( self.getMangledName("params"), self._computeParams() )
+
+    @property
+    def gamma(self):
+        """Amount of gamma correction.
+
+        In order to posterize the colors in a perceptually linear way, this filter
+        needs to know the gamma correction value.
+
+        The gamma-corrected space is only used during the processing; both the
+        input and output are "gamma-uncorrected".
+
+        If you need to apply gamma correction to the final image, see the GammaAdjust filter.
+
+        Float, default 2.2. Use the value 1.0 for no-op.
+
+        """
+        return self._gamma
+    @gamma.setter
+    def gamma(self, value):
+        self._gamma = int(value)
+        if self.finalQuad is not None:
+            self.finalQuad.setShaderInput( self.getMangledName("params"), self._computeParams() )
+
diff -Naur CommonFilters190_ref/Scanlines.py CommonFilters190_retro/Scanlines.py
--- CommonFilters190_ref/Scanlines.py	2015-01-17 14:12:04.103821000 +0200
+++ CommonFilters190_retro/Scanlines.py	2015-01-27 18:22:16.834048000 +0200
@@ -5,7 +5,8 @@
 
 from Filter import Filter, TextureInfo
 
-
+# Compositor Cg code snippet.
+#
 SCANLINES_BODY="""// Bright/dark band artifact that results from temporal aliasing (due to nearly same framerates)
 // when a CRT screen is filmed with a video camera (like sometimes seen in the background in old news broadcasts).
 //
@@ -22,16 +23,55 @@
 float arg  = ((1.0 - %(texcoord_txcolor)s.y) / (2.0*bandSize)) - (2.0*bandSpeed)*time;
 float trig = max(sin(arg*3.1415926535), 0.0);  // use only the positive half-wave to have a "pause" of half a period
 float bandValue = bandStrength * trig*trig;  // sin**2 looks better for this than just sin
-pixcolor += bandValue;
+pixcolor += bandValue;  // additive blend for this looks natural
+
 
-// Darkening of alternating lines.
+// Darkening of alternating lines + tinting by CRT pixel matrix.
 //
 const float lineThickness = %(k_scanlines_darkparams)s.x;
 const float field         = %(k_scanlines_darkparams)s.y;
 const float strength      = %(k_scanlines_darkparams)s.z;
 
-if ( int( int((1.0 - %(texcoord_txcolor)s.y) / %(texpix_txcolor)s.y)/lineThickness ) %% 2 != field )
-    pixcolor.rgb = (1.0 - strength) * pixcolor.rgb;
+// Pixel x,y indices (note: we flip y to have zero at the upper edge)
+int x = int( %(texcoord_txcolor)s.x / %(texpix_txcolor)s.x );
+int y = int( (1.0 - %(texcoord_txcolor)s.y) / %(texpix_txcolor)s.y );
+
+// Pixel brightness modifier
+float3 mult = float3(1.0);
+
+#define TINT_ENABLED %(enable_tint)d
+#if TINT_ENABLED == 1
+
+// Tint by CRT pixel matrix.
+//
+// We must use a switch to choose the mask vector since the arbfp1 profile does not allow
+// indexing an array with an arbitrary int.
+//
+const float3 crt[] = float3[]( float3(1.0,0.5,0.5), float3(0.5,1.0,0.5), float3(0.5,0.5,1.0) );
+int xmod3 = x %% 3;
+switch(xmod3)
+{
+    case 0:
+        mult *= crt[0];
+        break;
+    case 1:
+        mult *= crt[1];
+        break;
+    case 2:
+        mult *= crt[2];
+        break;
+    default:
+        break;
+}
+
+#endif
+
+// Darken.
+//
+if ( int( y/lineThickness ) %% 2 != field )
+    mult *= (1.0 - strength);
+
+pixcolor.rgb *= mult;
 
 """
 
@@ -71,6 +111,8 @@
         self.bandSpeed     = 0.75
         self.bandSize      = 1.0
 
+        self.enableTint    = False
+
     def onAttachPipeline(self):
         self.registerInputTexture(texName="color")
         self.registerCustomInput(inputType="float4", inputName="k_scanlines_bandparams")
@@ -88,7 +130,8 @@
         code = SCANLINES_BODY % { "texcoord_txcolor" : txcolor.texcoord,
                                   "texpix_txcolor"   : txcolor.texpix,
                                   "k_scanlines_bandparams" : self.getMangledName("k_scanlines_bandparams"),
-                                  "k_scanlines_darkparams" : self.getMangledName("k_scanlines_darkparams") }
+                                  "k_scanlines_darkparams" : self.getMangledName("k_scanlines_darkparams"),
+                                  "enable_tint" : self.enableTint }
         return ("scanlines", code, "// CRT TV scanlines and bright/dark banding filter\n")
 
     def onUpdate(self):
@@ -221,3 +264,22 @@
         if self.finalQuad is not None:
             self.finalQuad.setShaderInput( self.getMangledName("scanlines_bandparams"), self._computeBandParamsInput() )
 
+
+    @property
+    def enableTint(self):
+        """Enable/disable tinting by CRT pixel matrix.
+
+        Boolean, default False.
+
+        The pixel matrix is currently hardcoded as horizontal, with adjacent pixel columns
+        in the order R, G, B.
+
+        """
+        return self._enableTint
+    @enableTint.setter
+    def enableTint(self, value):
+        # This option affects the compositor code, so we must rebuild the pipeline.
+        if (not hasattr(self, "_enableTint")  or  value != self._enableTint)  and  self.pipeline is not None:
+            self.pipeline._needsCompile = True
+        self._enableTint = value
+
