Browse Source

General development of FilterManager and CommonFiltes

Josh Yelon 18 years ago
parent
commit
6ac5500f76

+ 141 - 32
direct/src/filter/CommonFilters.py

@@ -18,30 +18,19 @@ clunky approach.  - Josh
 from FilterManager import FilterManager
 from pandac.PandaModules import Point3, Vec3, Vec4
 from pandac.PandaModules import NodePath, PandaNode
+from pandac.PandaModules import Filename
 from pandac.PandaModules import RenderState, Texture, Shader
-
-HEADER = """//Cg
-
-void vshader(float4 vtx_position : POSITION,
-             out float4 l_position : POSITION,
-             out float4 l_texcoord : TEXCOORD0,
-             uniform float4 texpad_txcolor,
-             uniform float4x4 mat_modelproj)
-{
-  l_position=mul(mat_modelproj, vtx_position);
-  l_texcoord=(vtx_position.xzxz * texpad_txcolor) + texpad_txcolor;
-}
-"""
+import sys,os
 
 CARTOON_BODY="""
-float4 cartoondelta = k_cartoonseparation * texpix_txcolor.xwyw;
-float4 cartoon_p0 = l_texcoord + cartoondelta.xyzw;
+float4 cartoondelta = k_cartoonseparation * texpix_txnormal.xwyw;
+float4 cartoon_p0 = l_texcoordN + cartoondelta.xyzw;
 float4 cartoon_c0 = tex2D(k_txnormal, cartoon_p0.xy);
-float4 cartoon_p1 = l_texcoord - cartoondelta.xyzw;
+float4 cartoon_p1 = l_texcoordN - cartoondelta.xyzw;
 float4 cartoon_c1 = tex2D(k_txnormal, cartoon_p1.xy);
-float4 cartoon_p2 = l_texcoord + cartoondelta.wzyx;
+float4 cartoon_p2 = l_texcoordN + cartoondelta.wzyx;
 float4 cartoon_c2 = tex2D(k_txnormal, cartoon_p2.xy);
-float4 cartoon_p3 = l_texcoord - cartoondelta.wzyx;
+float4 cartoon_p3 = l_texcoordN - cartoondelta.wzyx;
 float4 cartoon_c3 = tex2D(k_txnormal, cartoon_p3.xy);
 float4 cartoon_mx = max(cartoon_c0,max(cartoon_c1,max(cartoon_c2,cartoon_c3)));
 float4 cartoon_mn = min(cartoon_c0,min(cartoon_c1,min(cartoon_c2,cartoon_c3)));
@@ -50,10 +39,9 @@ float  cartoon_thresh = dot(cartoon_trigger.xyz,float3(1,1,1));
 o_color = lerp(o_color, float4(0,0,0,1), cartoon_thresh);
 """
 
-CARTOON_PARAMS="""
-uniform float4 k_cartoonseparation,
-uniform float4 k_cartooncutoff,
-"""
+class FilterConfig:
+    pass
+
 class CommonFilters:
 
     """ Class CommonFilters implements certain common image postprocessing
@@ -64,10 +52,16 @@ class CommonFilters:
         self.configuration = {}
         self.cleanup()
 
+    def loadShader(self, name):
+        fn = os.path.join(os.path.abspath(os.path.dirname(__file__)), name)
+        print "loading shader: ", dir
+        return Shader.load(Filename.fromOsSpecific(fn))
+
     def cleanup(self):
         self.manager.cleanup()
         self.textures = {}
         self.finalQuad = None
+        self.bloom = []
 
     def reconfigure(self, fullrebuild, changed):
 
@@ -82,31 +76,98 @@ class CommonFilters:
             if (len(configuration) == 0):
                 return
 
-            needtexpix = False
             needtex = {}
             needtex["color"] = True
             if (configuration.has_key("CartoonInk")):
                 needtex["normal"] = True
+            if (configuration.has_key("Bloom")):
+                needtex["bloom0"] = True
+                needtex["bloom1"] = True
+                needtex["bloom2"] = True
+                needtex["bloom3"] = True
             for tex in needtex:
                 self.textures[tex] = Texture("scene-"+tex)
                 needtexpix = True
 
             self.finalQuad = self.manager.renderSceneInto(textures = self.textures)
     
-            text = HEADER
+            if (configuration.has_key("Bloom")):
+                bloomconf = configuration["Bloom"]
+                bloom0=self.textures["bloom0"]
+                bloom1=self.textures["bloom1"]
+                bloom2=self.textures["bloom2"]
+                bloom3=self.textures["bloom3"]
+                if (bloomconf.size == "large"):
+                    scale=8
+                    downsampler="filter-down4.sha"
+                elif (bloomconf.size == "medium"):
+                    scale=4
+                    downsampler="filter-copy.sha"
+                else:
+                    scale=2
+                    downsampler="filter-copy.sha"
+                self.bloom.append(self.manager.renderQuadInto(colortex=bloom0, div=2,     align=scale))
+                self.bloom.append(self.manager.renderQuadInto(colortex=bloom1, div=scale, align=scale))
+                self.bloom.append(self.manager.renderQuadInto(colortex=bloom2, div=scale, align=scale))
+                self.bloom.append(self.manager.renderQuadInto(colortex=bloom3, div=scale, align=scale))
+                self.bloom[0].setShaderInput("src", self.textures["color"])
+                self.bloom[0].setShader(self.loadShader("filter-bloomi.sha"))
+                self.bloom[1].setShaderInput("src", bloom0)
+                self.bloom[1].setShader(self.loadShader(downsampler))
+                self.bloom[2].setShaderInput("src", bloom1)
+                self.bloom[2].setShader(self.loadShader("filter-bloomx.sha"))
+                self.bloom[3].setShaderInput("src", bloom2)
+                self.bloom[3].setShader(self.loadShader("filter-bloomy.sha"))
+
+            text = "//Cg\n"
+            text += "void vshader(float4 vtx_position : POSITION,\n"
+            text += " out float4 l_position : POSITION,\n"
+            text += " uniform float4 texpad_txcolor,\n"
+            text += " uniform float4 texpix_txcolor,\n"
+            text += " out float4 l_texcoordC : TEXCOORD0,\n"
+            if (configuration.has_key("CartoonInk")):
+                text += " uniform float4 texpad_txnormal,\n"
+                text += " uniform float4 texpix_txnormal,\n"
+                text += " out float4 l_texcoordN : TEXCOORD1,\n"
+            if (configuration.has_key("Bloom")):
+                text += " uniform float4 texpad_txbloom3,\n"
+                text += " out float4 l_texcoordB : TEXCOORD2,\n"
+            text += " uniform float4x4 mat_modelproj)\n"
+            text += "{\n"
+            text += " l_position=mul(mat_modelproj, vtx_position);\n"
+            text += " l_texcoordC=(vtx_position.xzxz * texpad_txcolor) + texpad_txcolor;\n"
+            if (configuration.has_key("CartoonInk")):
+                text += " l_texcoordN=(vtx_position.xzxz * texpad_txnormal) + texpad_txnormal;\n"
+            if (configuration.has_key("Bloom")):
+                text += " l_texcoordB=(vtx_position.xzxz * texpad_txbloom3) + texpad_txbloom3;\n"
+            if (configuration.has_key("HalfPixelShift")):
+                text += " l_texcoordC+=texpix_txcolor*0.5;\n"
+                if (configuration.has_key("CartoonInk")):
+                    text += " l_texcoordN+=texpix_txnormal*0.5;\n"
+            text += "}\n"
+
             text += "void fshader(\n"
-            text += "float4 l_texcoord : TEXCOORD0,\n"
-            if (needtexpix):
-                text += "uniform float4 texpix_txcolor,\n"
+            text += "float4 l_texcoordC : TEXCOORD0,\n"
+            text += "uniform float4 texpix_txcolor,\n"
+            if (configuration.has_key("CartoonInk")):
+                text += "float4 l_texcoordN : TEXCOORD1,\n"
+                text += "uniform float4 texpix_txnormal,\n"
+            if (configuration.has_key("Bloom")):
+                text += "float4 l_texcoordB : TEXCOORD2,\n"
             for key in self.textures:
                 text += "uniform sampler2D k_tx" + key + ",\n"
             if (configuration.has_key("CartoonInk")):
-                text += CARTOON_PARAMS
+                text += "uniform float4 k_cartoonseparation,\n"
+                text += "uniform float4 k_cartooncutoff,\n"
             text += "out float4 o_color : COLOR)\n"
             text += "{\n"
-            text += " o_color = tex2D(k_txcolor, l_texcoord.xy);\n"
+            text += " o_color = tex2D(k_txcolor, l_texcoordC.xy);\n"
             if (configuration.has_key("CartoonInk")):
                 text += CARTOON_BODY
+            if (configuration.has_key("Bloom")):
+                text += "o_color = saturate(o_color);\n";
+                text += "float4 bloom = 0.5*tex2D(k_txbloom3, l_texcoordB.xy);\n"
+                text += "o_color = 1-((1-bloom)*(1-o_color));\n"
             text += "}\n"
     
             print "Using shader: ", text
@@ -120,6 +181,15 @@ class CommonFilters:
                 self.finalQuad.setShaderInput("cartoonseparation", Vec4(separation,0,separation,0))
                 self.finalQuad.setShaderInput("cartooncutoff", Vec4(cutoff,cutoff,cutoff,cutoff))
 
+        if (changed == "Bloom") or fullrebuild:
+            if (configuration.has_key("Bloom")):
+                bloomconf = configuration["Bloom"]
+                intensity = bloomconf.intensity * 3.0
+                self.bloom[0].setShaderInput("blend", bloomconf.blendx, bloomconf.blendy, bloomconf.blendz, bloomconf.blendw)
+                self.bloom[0].setShaderInput("trigger", bloomconf.mintrigger, 1.0/(bloomconf.maxtrigger-bloomconf.mintrigger), 0.0, 0.0)
+                self.bloom[0].setShaderInput("desat", bloomconf.desat)
+                self.bloom[3].setShaderInput("intensity", intensity, intensity, intensity, intensity)
+
     def setCartoonInk(self, separation=1, cutoff=0.3):
         fullrebuild = (self.configuration.has_key("CartoonInk") == False)
         self.configuration["CartoonInk"] = (separation, cutoff)
@@ -128,6 +198,45 @@ class CommonFilters:
     def delCartoonInk(self):
         if (self.configuration.has_key("CartoonInk")):
             del self.configuration["CartoonInk"]
-            self.reconfigure(True)
-
-
+            self.reconfigure(True, "CartoonInk")
+
+    def setBloom(self, blend=(0.3,0.4,0.3,0.0), mintrigger=0.6, maxtrigger=1.0, desat=0.6, intensity=1.0, size="medium"):
+        if (maxtrigger==None): maxtrigger=mintrigger+0.8
+        oldconfig = self.configuration.get("Bloom", None)
+        fullrebuild = True
+        if (oldconfig) and (oldconfig.size == size):
+            fullrebuild = False
+        newconfig = FilterConfig()
+        (newconfig.blendx, newconfig.blendy, newconfig.blendz, newconfig.blendw) = blend
+        newconfig.maxtrigger = maxtrigger
+        newconfig.mintrigger = mintrigger
+        newconfig.desat = desat
+        newconfig.intensity = intensity
+        newconfig.size = size
+        self.configuration["Bloom"] = newconfig
+        self.reconfigure(fullrebuild, "Bloom")
+
+    def delBloom(self):
+        if (self.configuration.has_key("Bloom")):
+            del self.configuration["Bloom"]
+            self.reconfigure(True, "Bloom")
+
+    def setHalfPixelShift(self):
+        fullrebuild = (self.configuration.has_key("HalfPixelShift") == False)
+        self.configuration["HalfPixelShift"] = 1
+        self.reconfigure(fullrebuild, "HalfPixelShift")
+
+    def delHalfPixelShift(self):
+        if (self.configuration.has_key("HalfPixelShift")):
+            del self.configuration["HalfPixelShift"]
+            self.reconfigure(True, "HalfPixelShift")
+
+    def setFSBloom(self):
+        fullrebuild = (self.configuration.has_key("FSBloom") == False)
+        self.configuration["FSBloom"] = 1
+        self.reconfigure(fullrebuild, "FSBloom")
+
+    def delFSBloom(self):
+        if (self.configuration.has_key("FSBloom")):
+            del self.configuration["FSBloom"]
+            self.reconfigure(True, "FSBloom")

+ 134 - 16
direct/src/filter/FilterManager.py

@@ -61,10 +61,63 @@ class FilterManager:
         self.win = win
         self.engine = win.getGsg().getEngine()
         self.region = region
+        self.wclears = self.getClears(self.win)
+        self.rclears = self.getClears(self.region)
         self.camera = cam
         self.caminit = cam.node().getInitialState()
-        self.scales = []
         self.buffers = []
+        self.sizes = []
+        self.nextsort = self.win.getSort() - 1000
+        self.basex = 0
+        self.basey = 0
+
+
+    def getClears(self,region):
+        clears = []
+        for i in range(GraphicsOutput.RTPCOUNT):
+            clears.append((region.getClearActive(i), region.getClearValue(i)))
+        return clears
+
+    def setClears(self,region,clears):
+        for i in range(GraphicsOutput.RTPCOUNT):
+            (active, value) = clears[i]
+            region.setClearActive(i, active)
+            region.setClearValue(i, value)
+
+    def setStackedClears(self, region, clears0, clears1):
+        clears = []
+        for i in range(GraphicsOutput.RTPCOUNT):
+            (active, value) = clears0[i]
+            if (active == 0):
+                (active, value) = clears1[i]
+            region.setClearActive(i, active)
+            region.setClearValue(i, value)
+        return clears
+
+    def isFullscreen(self):
+        return ((self.region.getLeft()   == 0.0) and
+                (self.region.getRight()  == 1.0) and
+                (self.region.getBottom() == 0.0) and
+                (self.region.getTop()    == 1.0))
+            
+    def getScaledSize(self, mul, div, align):
+
+        """ Calculate the size of the desired window. Not public. """
+
+        winx = self.win.getXSize()
+        winy = self.win.getYSize()
+
+        if (div != 1):
+            winx = ((winx+align-1) / align) * align
+            winy = ((winy+align-1) / align) * align
+            winx = winx / div
+            winy = winy / div
+
+        if (mul != 1):
+            winx = winx * mul
+            winy = winy * mul
+
+        return winx,winy
 
     def renderSceneInto(self, depthtex=False, colortex=False, normaltex=False, textures=None):
 
@@ -77,9 +130,9 @@ class FilterManager:
         To elaborate on how this all works:
 
         * An offscreen buffer is created.  It is set up to mimic
-          the original window - it is the same size, uses the
-          same clear colors, and contains a DisplayRegion that
-          uses the original camera.
+          the original display region - it is the same size,
+          uses the same clear colors, and contains a DisplayRegion
+          that uses the original camera.
 
         * A fullscreen quad and an orthographic camera to render
           that quad are both created.  The original camera is
@@ -90,6 +143,18 @@ class FilterManager:
           offscreen buffer.  A shader is applied that tints the
           results pink.
 
+        * Automatic shader generation is enabled by default for
+          the main camera.  You can override this by setting
+          shaders on individual nodes, or on the root of your
+          scene graph, but if you do, your own shaders need to
+          generate the outputs that the filter manager is expecting.
+
+        * All clears are disabled on the original display region.
+          If the display region fills the whole window, then clears
+          are disabled on the original window as well.  It is
+          assumed that rendering the full-screen quad eliminates
+          the need to do clears.
+
         Hence, the original window which used to contain the actual
         scene, now contains a pink-tinted quad with a texture of the
         scene.  It is assumed that the user will replace the shader
@@ -104,7 +169,11 @@ class FilterManager:
 
         texgroup = (depthtex, colortex, normaltex, None)
 
-        buffer = self.createBuffer("filter-base", base.win.getXSize(), base.win.getYSize(), texgroup)
+        # Choose the size of the offscreen buffer.
+
+        winx = self.win.getXSize()
+        winy = self.win.getYSize()
+        buffer = self.createBuffer("filter-base", winx, winy, texgroup)
 
         if (buffer == None):
             return None
@@ -137,26 +206,68 @@ class FilterManager:
         
         self.region.setCamera(quadcam)
 
-        buffer.getDisplayRegion(0).setCamera(self.camera)
-        buffer.getDisplayRegion(0).setActive(1)
+        dr = buffer.getDisplayRegion(0)
+        self.setStackedClears(dr, self.rclears, self.wclears)
+        if (normaltex):
+            dr.setClearActive(GraphicsOutput.RTPAuxRgba0, 1)
+            dr.setClearValue(GraphicsOutput.RTPAuxRgba0, Vec4(0.0,0.0,0.0,0.0))
+        self.region.disableClears()
+        if (self.isFullscreen()):
+            self.win.disableClears()
+        dr.setCamera(self.camera)
+        dr.setActive(1)
 
-        self.scales.append(1)
         self.buffers.append(buffer)
+        self.sizes.append((1, 1, 1))
 
         return quad
 
-    def renderQuadInto(self, scale=1, depthtex=None, colortex=None, auxtex0=None, auxtex1=None):
+    def renderQuadInto(self, mul=1, div=1, align=1, depthtex=None, colortex=None, auxtex0=None, auxtex1=None):
 
         """ Creates an offscreen buffer for an intermediate
         computation. Installs a quad into the buffer.  Returns
-        the fullscreen quad. """
+        the fullscreen quad.  The size of the buffer is initially
+        equal to the size of the main window.  The parameters 'mul',
+        'div', and 'align' can be used to adjust that size. """
+
+        texgroup = (depthtex, colortex, auxtex0, auxtex1)
+
+        winx, winy = self.getScaledSize(mul, div, align)
+        
+        buffer = self.createBuffer("filter-stage", winx, winy, texgroup, depthbits=0)
+
+        if (buffer == None):
+            return None
 
-        self.notify.error('renderQuadInto not implemented yet.')
-        return None
+        cm = CardMaker("filter-stage-quad")
+        cm.setFrameFullscreenQuad()
+        quad = NodePath(cm.generate())
+        quad.setDepthTest(0)
+        quad.setDepthWrite(0)
+        quad.setColor(Vec4(1,0.5,0.5,1))
 
-    def createBuffer(self, name, xsize, ysize, texgroup):
+        quadcamnode = Camera("filter-quad-cam")
+        lens = OrthographicLens()
+        lens.setFilmSize(2, 2)
+        lens.setFilmOffset(0, 0)
+        lens.setNearFar(-1000, 1000)
+        quadcamnode.setLens(lens)
+        quadcam = quad.attachNewNode(quadcamnode)
+        
+        buffer.getDisplayRegion(0).setCamera(quadcam)
+        buffer.getDisplayRegion(0).setActive(1)
+
+        self.buffers.append(buffer)
+        self.sizes.append((1, 1, 1))
+        
+        return quad
+
+    def createBuffer(self, name, xsize, ysize, texgroup, depthbits=1):
         """ Low-level buffer creation.  Not intended for public use. """
+
+        print "Creating buffer: ",xsize,ysize,texgroup,depthbits
         winprops = WindowProperties()
+        winprops.setSize(xsize, ysize)
         props = FrameBufferProperties()
         props.setRgbColor(1)
         props.setDepthBits(1)
@@ -177,6 +288,10 @@ class FilterManager:
             buffer.addRenderTexture(auxtex0, GraphicsOutput.RTMBindOrCopy, GraphicsOutput.RTPAuxRgba0)
         if (auxtex1):
             buffer.addRenderTexture(auxtex1, GraphicsOutput.RTMBindOrCopy, GraphicsOutput.RTPAuxRgba1)
+        buffer.setSort(self.nextsort)
+        buffer.disableClears()
+        buffer.getDisplayRegion(0).disableClears()
+        self.nextsort += 1
         return buffer
 
 
@@ -187,9 +302,12 @@ class FilterManager:
         for buffer in self.buffers:
             buffer.clearRenderTextures()
             self.engine.removeWindow(buffer)
-        self.scales = []
         self.buffers = []
-        self.region.setCamera(self.camera)
+        self.sizes = []
+        self.setClears(self.win, self.wclears)
+        self.setClears(self.region, self.rclears)
         self.camera.node().setInitialState(self.caminit)
-
+        self.nextsort = self.win.getSort() - 1000
+        self.basex = 0
+        self.basey = 0
 

+ 85 - 0
direct/src/filter/filter-bloomi.sha

@@ -0,0 +1,85 @@
+//Cg
+//
+// blend.rgb
+//
+//   This shader converts to black-and-white before calculating
+//   scene brightness.  To do this, it uses a weighted average of
+//   R,G,B.  The blend parameter controls the weighting.
+//
+// desat.x
+//
+//   Desaturation level.  If zero, the bloom's color is equal to
+//   the color of the input pixel.  If one, the bloom's color is
+//   white.
+//
+// trigger.x
+//
+//   Must be equal to mintrigger.
+//
+//   mintrigger is the minimum brightness to trigger a bloom,
+//   and maxtrigger is the brightness at which the bloom
+//   reaches maximum intensity.
+//
+// trigger.y
+//
+//   Must be equal to (1.0/(maxtrigger-mintrigger)) where
+//   
+//   mintrigger is the minimum brightness to trigger a bloom,
+//   and maxtrigger is the brightness at which the bloom
+//   reaches maximum intensity.
+//
+
+
+void vshader(float4 vtx_position : POSITION,
+             out float4 l_position : POSITION,
+             out float2 l_texcoordNW : TEXCOORD0,
+             out float2 l_texcoordNE : TEXCOORD1,
+             out float2 l_texcoordSW : TEXCOORD2,
+             out float2 l_texcoordSE : TEXCOORD3,
+             uniform float4 texpad_src,
+             uniform float4 texpix_src,
+             uniform float4x4 mat_modelproj)
+{
+  l_position=mul(mat_modelproj, vtx_position);
+  float2 c=(vtx_position.xz * texpad_src.xy) + texpad_src.xy;
+  float4 offs = texpix_src * 0.5;
+  l_texcoordNW = c + float2( offs.x, -offs.y);
+  l_texcoordNE = c + float2( offs.x,  offs.y);
+  l_texcoordSW = c + float2(-offs.x, -offs.y);
+  l_texcoordSE = c + float2(-offs.x,  offs.y);
+}
+
+void fshader(float2 l_texcoordNW : TEXCOORD0,
+             float2 l_texcoordNE : TEXCOORD1,
+             float2 l_texcoordSW : TEXCOORD2,
+             float2 l_texcoordSE : TEXCOORD3,
+             uniform sampler2D k_src : TEXUNIT0,
+             out float4 o_color : COLOR,
+             uniform float4 k_blend,
+             uniform float4 k_trigger,
+             uniform float4 k_desat
+             )
+{
+  float4 inputNW = tex2D(k_src, l_texcoordNW);
+  float briteNW = dot(inputNW, k_blend);
+  float scaleNW = saturate((briteNW - k_trigger.x) * k_trigger.y);
+  float4 colorNW = scaleNW * lerp(inputNW, float4(1,1,1,1), k_desat.x);
+
+  float4 inputNE = tex2D(k_src, l_texcoordNE);
+  float briteNE = dot(inputNE, k_blend);
+  float scaleNE = saturate((briteNE - k_trigger.x) * k_trigger.y);
+  float4 colorNE = scaleNE * lerp(inputNE, float4(1,1,1,1), k_desat.x);
+
+  float4 inputSW = tex2D(k_src, l_texcoordSW);
+  float briteSW = dot(inputSW, k_blend);
+  float scaleSW = saturate((briteSW - k_trigger.x) * k_trigger.y);
+  float4 colorSW = scaleSW * lerp(inputSW, float4(1,1,1,1), k_desat.x);
+
+  float4 inputSE = tex2D(k_src, l_texcoordSE);
+  float briteSE = dot(inputSE, k_blend);
+  float scaleSE = saturate((briteSE - k_trigger.x) * k_trigger.y);
+  float4 colorSE = scaleSE * lerp(inputSE, float4(1,1,1,1), k_desat.x);
+
+  o_color = (colorNW + colorNE + colorSW + colorSE) * 0.25;
+}
+

+ 47 - 0
direct/src/filter/filter-bloomx.sha

@@ -0,0 +1,47 @@
+//Cg
+
+void vshader(float4 vtx_position : POSITION,
+             out float4 l_position : POSITION,
+             out float4 l_texcoord0 : TEXCOORD0,
+             out float4 l_texcoord1 : TEXCOORD1,
+             out float4 l_texcoord2 : TEXCOORD2,
+             uniform float4 texpad_src,
+             uniform float4 texpix_src,
+             uniform float4x4 mat_modelproj)
+{
+  l_position=mul(mat_modelproj, vtx_position);
+  float2 c=(vtx_position.xz * texpad_src.xy) + texpad_src.xy;
+  float offset = texpix_src.x;
+  l_texcoord0 = float4(c.x-offset* -4, c.x-offset* -3, c.x-offset* -2, c.y);
+  l_texcoord1 = float4(c.x-offset* -1, c.x-offset*  0, c.x-offset*  1, c.y);
+  l_texcoord2 = float4(c.x-offset*  2, c.x-offset*  3, c.x-offset*  4, c.y);
+}
+
+void fshader(float4 l_texcoord0 : TEXCOORD0,
+             float4 l_texcoord1 : TEXCOORD1,
+             float4 l_texcoord2 : TEXCOORD2,
+             uniform sampler2D k_src : TEXUNIT0,
+             out float4 o_color : COLOR) {
+  float4 color = float4(0,0,0,0);
+//  color  =  10 * tex2D(k_src, l_texcoord0.xw);
+//  color +=  45 * tex2D(k_src, l_texcoord0.yw);
+//  color += 120 * tex2D(k_src, l_texcoord0.zw);
+//  color += 210 * tex2D(k_src, l_texcoord1.xw);
+//  color += 252 * tex2D(k_src, l_texcoord1.yw);
+//  color += 210 * tex2D(k_src, l_texcoord1.zw);
+//  color += 120 * tex2D(k_src, l_texcoord2.xw);
+//  color +=  45 * tex2D(k_src, l_texcoord2.yw);
+//  color +=  10 * tex2D(k_src, l_texcoord2.zw);
+//  o_color = color / 1022.0;
+
+  color  =  50 * tex2D(k_src, l_texcoord0.xw);
+  color += 100 * tex2D(k_src, l_texcoord0.yw);
+  color += 150 * tex2D(k_src, l_texcoord0.zw);
+  color += 200 * tex2D(k_src, l_texcoord1.xw);
+  color += 200 * tex2D(k_src, l_texcoord1.yw);
+  color += 200 * tex2D(k_src, l_texcoord1.zw);
+  color += 150 * tex2D(k_src, l_texcoord2.xw);
+  color += 100 * tex2D(k_src, l_texcoord2.yw);
+  color +=  50 * tex2D(k_src, l_texcoord2.zw);
+  o_color = color / 1200.0;
+}

+ 38 - 0
direct/src/filter/filter-bloomy.sha

@@ -0,0 +1,38 @@
+//Cg
+
+void vshader(float4 vtx_position : POSITION,
+             out float4 l_position : POSITION,
+             out float4 l_texcoord0 : TEXCOORD0,
+             out float4 l_texcoord1 : TEXCOORD1,
+             out float4 l_texcoord2 : TEXCOORD2,
+             uniform float4 texpad_src,
+             uniform float4 texpix_src,
+             uniform float4x4 mat_modelproj)
+{
+  l_position=mul(mat_modelproj, vtx_position);
+  float2 c=(vtx_position.xz * texpad_src.xy) + texpad_src.xy;
+  float offset = texpix_src.y;
+  l_texcoord0 = float4(c.y-offset* -4, c.y-offset* -3, c.y-offset* -2, c.x);
+  l_texcoord1 = float4(c.y-offset* -1, c.y-offset*  0, c.y-offset*  1, c.x);
+  l_texcoord2 = float4(c.y-offset*  2, c.y-offset*  3, c.y-offset*  4, c.x);
+}
+
+void fshader(float4 l_texcoord0 : TEXCOORD0,
+             float4 l_texcoord1 : TEXCOORD1,
+             float4 l_texcoord2 : TEXCOORD2,
+             uniform sampler2D k_src : TEXUNIT0,
+             uniform float4 k_intensity,
+             out float4 o_color : COLOR) {
+  float4 color = float4(0,0,0,0);
+  color  =  50 * tex2D(k_src, l_texcoord0.wx);
+  color += 100 * tex2D(k_src, l_texcoord0.wy);
+  color += 150 * tex2D(k_src, l_texcoord0.wz);
+  color += 200 * tex2D(k_src, l_texcoord1.wx);
+  color += 200 * tex2D(k_src, l_texcoord1.wy);
+  color += 200 * tex2D(k_src, l_texcoord1.wz);
+  color += 150 * tex2D(k_src, l_texcoord2.wx);
+  color += 100 * tex2D(k_src, l_texcoord2.wy);
+  color +=  50 * tex2D(k_src, l_texcoord2.wz);
+  o_color = color / 1200.0;
+  o_color = o_color * k_intensity;
+}

+ 20 - 0
direct/src/filter/filter-copy.sha

@@ -0,0 +1,20 @@
+//Cg
+
+
+void vshader(float4 vtx_position : POSITION,
+             out float4 l_position : POSITION,
+             out float2 l_texcoord : TEXCOORD0,
+             uniform float4 texpad_src,
+             uniform float4x4 mat_modelproj)
+{
+  l_position=mul(mat_modelproj, vtx_position);
+  l_texcoord = (vtx_position.xz * texpad_src.xy) + texpad_src.xy;
+}
+
+void fshader(float2 l_texcoord : TEXCOORD0,
+             uniform sampler2D k_src : TEXUNIT0,
+             out float4 o_color : COLOR)
+{
+  o_color = tex2D(k_src, l_texcoord);
+}
+

+ 33 - 0
direct/src/filter/filter-down4.sha

@@ -0,0 +1,33 @@
+//Cg
+
+void vshader(float4 vtx_position : POSITION,
+             out float4 l_position : POSITION,
+             out float2 l_texcoordNW : TEXCOORD0,
+             out float2 l_texcoordNE : TEXCOORD1,
+             out float2 l_texcoordSW : TEXCOORD2,
+             out float2 l_texcoordSE : TEXCOORD3,
+             uniform float4 texpad_src,
+             uniform float4 texpix_src,
+             uniform float4x4 mat_modelproj)
+{
+  l_position=mul(mat_modelproj, vtx_position);
+  float2 c=(vtx_position.xz * texpad_src.xy) + texpad_src.xy;
+  l_texcoordNW = c + float2( texpix_src.x, -texpix_src.y);
+  l_texcoordNE = c + float2( texpix_src.x,  texpix_src.y);
+  l_texcoordSW = c + float2(-texpix_src.x, -texpix_src.y);
+  l_texcoordSE = c + float2(-texpix_src.x,  texpix_src.y);
+}
+
+void fshader(float2 l_texcoordNW : TEXCOORD0,
+             float2 l_texcoordNE : TEXCOORD1,
+             float2 l_texcoordSW : TEXCOORD2,
+             float2 l_texcoordSE : TEXCOORD3,
+             uniform sampler2D k_src : TEXUNIT0,
+             out float4 o_color : COLOR) {
+  float4 colorNW = tex2D(k_src, l_texcoordNW);
+  float4 colorNE = tex2D(k_src, l_texcoordNE);
+  float4 colorSW = tex2D(k_src, l_texcoordSW);
+  float4 colorSE = tex2D(k_src, l_texcoordSE);
+  o_color = (colorNW + colorNE + colorSW + colorSE);
+}
+