mirror of
https://github.com/joncampbell123/dosbox-x.git
synced 2025-05-08 19:32:39 +08:00
777 lines
20 KiB
HLSL
777 lines
20 KiB
HLSL
/*
|
|
Copyright (C) 2003 Ryan A. Nunn
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
//
|
|
// ** 2xSaI **
|
|
//
|
|
// 2xSaI algorithm is Copyright (c) 1999-2001 by Derek Liauw Kie Fa.
|
|
//
|
|
// 2xSaI is free under GPL
|
|
//
|
|
// Adapted by Ryan A. Nunn into Pixel and Vertex Shaders to be used with the
|
|
// Scaling2D entry in the Beyond3D/ATI Shader Competition
|
|
//
|
|
// Download original C/ASM code here: http://elektron.its.tudelft.nl/~dalikifa/
|
|
//
|
|
// Notes about the creation of the shaders
|
|
//
|
|
// The differences from the C/ASM code are quite substantial, which would be
|
|
// plainly obvious to anyone who has worked with the C/ASM versions of these
|
|
// algorithms.
|
|
//
|
|
// The reasons for this are as follows:
|
|
// 1) Can only output a single pixel at a time (Note MRT wouldn't be useful)
|
|
// 2) 'Small' instruction count limits
|
|
// 3) No program flow control
|
|
//
|
|
// As such, the algorithm couldn't be simply converted into pixel shaders
|
|
// because multiple nested if statements were used. While this may be fairly
|
|
// fast on a CPU, it is very unsuitable for a pixel shader. So I decided to do
|
|
// things differently. I decided that I should instead write boolean
|
|
// expressions for each of the possible values for each product, and convert
|
|
// those into pixel shaders with a final combining stage
|
|
//
|
|
// An example of one of the expressions is:
|
|
// useColA = (AD && BC && BD) || (((AC && AF && BJ && !BE) || (AD && AE && BL)) && !BC);
|
|
//
|
|
// That expression represents which colours much and must not be the same in
|
|
// order for product0 to be colorA
|
|
//
|
|
// After doing all that, I had managed to convert the algorithm from working
|
|
// out all the products at the same time, to working out each product
|
|
// individually. The algorithm would now be suitable for conversion into pixel
|
|
// shaders.
|
|
//
|
|
|
|
#include "Scaling.inc"
|
|
|
|
// The name of this effect
|
|
string name : NAME = "2xSaI (Gamma Corrected)";
|
|
float scaling : SCALING = 2.0;
|
|
|
|
//
|
|
// Techniques
|
|
//
|
|
|
|
// combineTechnique: Final combine steps. Outputs to destination frame buffer
|
|
string combineTechique : COMBINETECHNIQUE = "Combine_2xSaI";
|
|
|
|
// preprocessTechnique: PreProcessing steps. Outputs to WorkingTexture
|
|
string preprocessTechique : PREPROCESSTECHNIQUE = "Preprocess_2xSaI";
|
|
|
|
|
|
//
|
|
// Textures and Samplers
|
|
//
|
|
|
|
|
|
//
|
|
// Texture Gen Shaders
|
|
//
|
|
|
|
|
|
//
|
|
// Vertex Shader Output
|
|
//
|
|
|
|
// Texel Locations
|
|
//
|
|
// -1 0 1 2
|
|
// -1 I E F J
|
|
// 0 G A B K
|
|
// 1 H C D L
|
|
// 2 M N O P
|
|
|
|
struct VS_OUTPUT_PRODUCT0
|
|
{
|
|
float4 Position : POSITION;
|
|
float2 colorA : TEXCOORD0;
|
|
float2 colorB : TEXCOORD1;
|
|
float2 colorC : TEXCOORD2;
|
|
float2 colorD : TEXCOORD3;
|
|
float2 colorE : TEXCOORD4;
|
|
float2 colorF : TEXCOORD5;
|
|
float2 colorH : TEXCOORD6;
|
|
float2 colorJ : TEXCOORD7;
|
|
};
|
|
|
|
struct VS_OUTPUT_PRODUCT1
|
|
{
|
|
float4 Position : POSITION;
|
|
float2 colorA : TEXCOORD0;
|
|
float2 colorC : TEXCOORD1;
|
|
float2 colorB : TEXCOORD2;
|
|
float2 colorD : TEXCOORD3;
|
|
float2 colorG : TEXCOORD4;
|
|
float2 colorH : TEXCOORD5;
|
|
float2 colorF : TEXCOORD6;
|
|
float2 colorM : TEXCOORD7;
|
|
};
|
|
|
|
struct VS_OUTPUT_PRODUCT2_PASS0
|
|
{
|
|
float4 Position : POSITION;
|
|
float2 colorA : TEXCOORD0;
|
|
float2 colorB : TEXCOORD1;
|
|
float2 colorC : TEXCOORD2;
|
|
float2 colorD : TEXCOORD3;
|
|
};
|
|
|
|
struct VS_OUTPUT_PRODUCT2_PASS1
|
|
{
|
|
float4 Position : POSITION;
|
|
float2 colorA : TEXCOORD0;
|
|
float2 colorB : TEXCOORD1;
|
|
float2 colorG : TEXCOORD2;
|
|
float2 colorE : TEXCOORD3;
|
|
float2 colorK : TEXCOORD4;
|
|
float2 colorF : TEXCOORD5;
|
|
};
|
|
|
|
struct VS_OUTPUT_PRODUCT2_PASS2
|
|
{
|
|
float4 Position : POSITION;
|
|
float2 colorA : TEXCOORD0;
|
|
float2 colorB : TEXCOORD1;
|
|
float2 colorL : TEXCOORD2;
|
|
float2 colorO : TEXCOORD3;
|
|
float2 colorH : TEXCOORD4;
|
|
float2 colorN : TEXCOORD5;
|
|
};
|
|
|
|
struct VS_OUTPUT_COMBINE
|
|
{
|
|
float4 Position : POSITION;
|
|
float2 colorA : TEXCOORD0;
|
|
float2 colorB : TEXCOORD1;
|
|
float2 colorC : TEXCOORD2;
|
|
float2 colorD : TEXCOORD3;
|
|
float2 Selector : TEXCOORD4;
|
|
};
|
|
|
|
//
|
|
// Vertex Shaders
|
|
//
|
|
|
|
VS_OUTPUT_PRODUCT0 VS_Product0(
|
|
float3 Position : POSITION,
|
|
float2 TexCoord : TEXCOORD0)
|
|
{
|
|
VS_OUTPUT_PRODUCT0 Out = (VS_OUTPUT_PRODUCT0)0;
|
|
|
|
Out.Position = mul(float4(Position, 1), WorldViewProjection); // Matrix multipliy
|
|
Out.colorA = TexCoord;
|
|
Out.colorB = TexCoord + TexelSize * float2( 1, 0);
|
|
Out.colorC = TexCoord + TexelSize * float2( 0, 1);
|
|
Out.colorD = TexCoord + TexelSize * float2( 1, 1);
|
|
Out.colorF = TexCoord + TexelSize * float2( 1,-1);
|
|
Out.colorH = TexCoord + TexelSize * float2(-1, 1);
|
|
|
|
Out.colorE = TexCoord + TexelSize * float2( 0,-1);
|
|
Out.colorJ = TexCoord + TexelSize * float2( 2,-1);
|
|
|
|
return Out;
|
|
}
|
|
|
|
VS_OUTPUT_PRODUCT1 VS_Product1(
|
|
float3 Position : POSITION,
|
|
float2 TexCoord : TEXCOORD0)
|
|
{
|
|
VS_OUTPUT_PRODUCT1 Out = (VS_OUTPUT_PRODUCT1)0;
|
|
|
|
Out.Position = mul(float4(Position, 1), WorldViewProjection); // Matrix multipliy
|
|
Out.colorA = TexCoord;
|
|
Out.colorB = TexCoord + TexelSize * float2( 1, 0);
|
|
Out.colorC = TexCoord + TexelSize * float2( 0, 1);
|
|
Out.colorD = TexCoord + TexelSize * float2( 1, 1);
|
|
Out.colorF = TexCoord + TexelSize * float2( 1,-1);
|
|
Out.colorH = TexCoord + TexelSize * float2(-1, 1);
|
|
|
|
Out.colorG = TexCoord + TexelSize * float2(-1, 0);
|
|
Out.colorM = TexCoord + TexelSize * float2(-1, 2);
|
|
|
|
return Out;
|
|
}
|
|
|
|
VS_OUTPUT_PRODUCT2_PASS0 VS_Product2_Pass0(
|
|
float3 Position : POSITION,
|
|
float2 TexCoord : TEXCOORD0)
|
|
{
|
|
VS_OUTPUT_PRODUCT2_PASS0 Out = (VS_OUTPUT_PRODUCT2_PASS0)0;
|
|
|
|
Out.Position = mul(float4(Position, 1), WorldViewProjection); // Matrix multipliy
|
|
Out.colorA = TexCoord;
|
|
Out.colorB = TexCoord + TexelSize * float2( 1, 0);
|
|
Out.colorC = TexCoord + TexelSize * float2( 0, 1);
|
|
Out.colorD = TexCoord + TexelSize * float2( 1, 1);
|
|
|
|
return Out;
|
|
}
|
|
|
|
VS_OUTPUT_PRODUCT2_PASS1 VS_Product2_Pass1 (
|
|
float3 Position : POSITION,
|
|
float2 TexCoord : TEXCOORD0)
|
|
{
|
|
VS_OUTPUT_PRODUCT2_PASS1 Out = (VS_OUTPUT_PRODUCT2_PASS1)0;
|
|
|
|
Out.Position = mul(float4(Position, 1), WorldViewProjection); // Matrix multipliy
|
|
Out.colorA = TexCoord;
|
|
Out.colorB = TexCoord + TexelSize * float2( 1, 0);
|
|
Out.colorG = TexCoord + TexelSize * float2(-1, 0);
|
|
Out.colorE = TexCoord + TexelSize * float2( 0,-1);
|
|
Out.colorK = TexCoord + TexelSize * float2( 2, 0);
|
|
Out.colorF = TexCoord + TexelSize * float2( 1,-1);
|
|
|
|
return Out;
|
|
}
|
|
|
|
VS_OUTPUT_PRODUCT2_PASS2 VS_Product2_Pass2 (
|
|
float3 Position : POSITION,
|
|
float2 TexCoord : TEXCOORD0)
|
|
{
|
|
VS_OUTPUT_PRODUCT2_PASS2 Out = (VS_OUTPUT_PRODUCT2_PASS2)0;
|
|
|
|
Out.Position = mul(float4(Position, 1), WorldViewProjection); // Matrix multipliy
|
|
Out.colorA = TexCoord;
|
|
Out.colorB = TexCoord + TexelSize * float2( 1, 0);
|
|
Out.colorL = TexCoord + TexelSize * float2( 2, 1);
|
|
Out.colorO = TexCoord + TexelSize * float2( 1, 2);
|
|
Out.colorH = TexCoord + TexelSize * float2(-1, 1);
|
|
Out.colorN = TexCoord + TexelSize * float2( 0, 2);
|
|
|
|
return Out;
|
|
}
|
|
|
|
VS_OUTPUT_COMBINE VS_Combine(
|
|
float3 Position : POSITION,
|
|
float2 TexCoord : TEXCOORD0)
|
|
{
|
|
VS_OUTPUT_COMBINE Out = (VS_OUTPUT_COMBINE)0;
|
|
|
|
Out.Position = mul(float4(Position, 1), WorldViewProjection); // Matrix multipliy
|
|
Out.colorA = TexCoord;
|
|
Out.colorB = TexCoord + TexelSize * float2( 1, 0);
|
|
Out.colorC = TexCoord + TexelSize * float2( 0, 1);
|
|
Out.colorD = TexCoord + TexelSize * float2( 1, 1);
|
|
Out.Selector = TexCoord*SourceDims;
|
|
|
|
return Out;
|
|
}
|
|
|
|
|
|
//
|
|
// Pixel Shaders
|
|
//
|
|
|
|
//
|
|
// This pixel shader is used for the product0 and product1 preprocesses steps.
|
|
// By purely changing the vertex shader, does the effect of this pixel shader change.
|
|
// What happens is the texture coords become mirrored across the xy diagonal.
|
|
//
|
|
// This has been hand coded to reduce instruction counts so this can run in 1 pass, per
|
|
// product. This code is likely to run very poorly on NV3x hardware.
|
|
//
|
|
PIXELSHADER PS_Product0_1 = asm
|
|
{
|
|
ps_2_0
|
|
|
|
// Some opcode 'aliases' for bools
|
|
#define or add_sat
|
|
#define and mul
|
|
#define and_or mad_sat
|
|
|
|
// Same thing, but partial precision (using mad_sat_pp is causing 'issues')
|
|
#define or_pp add_sat_pp
|
|
#define and_pp mul_pp
|
|
#define and_or_pp mad_sat
|
|
|
|
//
|
|
// Constants
|
|
//
|
|
|
|
def c0, 0, 1, 0.35, 0.7
|
|
#define zero c0.r
|
|
#define one c0.g
|
|
#define ret_B c0.b
|
|
#define ret_A c0.a
|
|
|
|
//def c2, TexelSize // Set by the effect
|
|
#define TexelSize c2
|
|
|
|
|
|
|
|
//
|
|
// Samplers
|
|
//
|
|
|
|
// The only sampler we need. It is set by the effect
|
|
dcl_2d s0 // SourceSampler
|
|
|
|
|
|
//
|
|
// Texture coords. These match VS_OUTPUT_PRODUCT0
|
|
//
|
|
|
|
dcl t0.xy // input.colorA (-TexelSize -> colorI)
|
|
dcl t1.xy // input.colorB (+TexelSize -> colorL)
|
|
dcl t2.xy // input.colorC
|
|
dcl t3.xy // input.colorD
|
|
dcl t4.xy // input.colorE
|
|
dcl t5.xy // input.colorF
|
|
dcl t6.xy // input.colorH
|
|
dcl t7.xy // input.colorJ
|
|
|
|
|
|
//
|
|
// The code
|
|
//
|
|
|
|
|
|
// Sample the first 6 textures (ABCDEF)
|
|
texld_pp r5, t0, s0 // colorA
|
|
texld_pp r6, t1, s0 // colorB
|
|
texld_pp r7, t2, s0 // colorC
|
|
texld_pp r8, t3, s0 // colorD
|
|
texld_pp r9, t4, s0 // colorE
|
|
texld_pp r10, t5, s0 // colorF
|
|
|
|
//
|
|
// Note that when we do the initial comparisons, we actually check to see
|
|
// if any texels are different, rather than all same. This allows for an
|
|
// optimization, since it requires less instructions (3 less per 4 comparisons)
|
|
//
|
|
// The sub finds the differences
|
|
// the dp3 will make the diffs all positive, and then combine them into a
|
|
// single component of the register.
|
|
//
|
|
|
|
|
|
//
|
|
// R2 Register. Contains A==C, B==C, A==D, B==D
|
|
//
|
|
#define AC r2.a
|
|
#define BC r2.r
|
|
#define AD r2.g
|
|
#define BD r2.b
|
|
|
|
// Calc A!=C
|
|
sub_pp r0, r5, r7 // 0
|
|
dp4_pp AC, r0, r0 // 1
|
|
|
|
// Calc B!=C
|
|
sub_pp r0, r6, r7 // 2
|
|
dp4_pp BC, r0, r0 // 3
|
|
|
|
// Calc A!=D
|
|
sub_pp r0, r5, r8 // 4
|
|
dp4_pp AD, r0, r0 // 5
|
|
|
|
// Calc B!=D
|
|
sub_pp r0, r6, r8 // 6
|
|
dp4_pp BD, r0, r0 // 7
|
|
|
|
// Invert register: r2 = !r2
|
|
cmp_pp r2, -r2, one, zero // 8
|
|
|
|
|
|
//
|
|
// R3 Register. Contains A==E, B==E, A==F, B==F
|
|
//
|
|
#define AE r3.a
|
|
#define BE r3.r
|
|
#define AF r3.g
|
|
#define BF r3.b
|
|
|
|
// Calc A!=E
|
|
sub_pp r0, r5, r9 // 9
|
|
dp4_pp AE, r0, r0 // 10
|
|
|
|
// Calc B!=E
|
|
sub_pp r0, r6, r9 // 11
|
|
dp4_pp BE, r0, r0 // 12
|
|
|
|
// Calc A!=F
|
|
sub_pp r0, r5, r10 // 13
|
|
dp4_pp AF, r0, r0 // 14
|
|
|
|
// Calc B!=F
|
|
sub_pp r0, r6, r10 // 15
|
|
dp4_pp BF, r0, r0 // 16
|
|
|
|
// Invert register: r3 = !r3
|
|
cmp_pp r3, -r3, one, zero // 17
|
|
|
|
|
|
|
|
// Sample final 4 textures (colorH, colorJ, colorI, and colorL)
|
|
sub r0.xy, t0, TexelSize // 18
|
|
add r1.xy, t1, TexelSize // 19
|
|
texld_pp r7, t6, s0 // colorH
|
|
texld_pp r8, t7, s0 // colorJ
|
|
texld_pp r9, r0, s0 // colorI -> input.colorA-texelSize
|
|
texld_pp r10, r1, s0 // colorL -> input.colorB+texelSize
|
|
|
|
|
|
//
|
|
// R4 Register. Contains A==H, B==J, A==I, B==L
|
|
//
|
|
|
|
#define AH r4.a
|
|
#define BJ r4.r
|
|
#define AI r4.g
|
|
#define BL r4.b
|
|
|
|
// Calc A!=H
|
|
sub_pp r0, r5, r7 // 20
|
|
dp4_pp AH, r0, r0 // 21
|
|
|
|
// Calc B!=J
|
|
sub_pp r0, r6, r8 // 22
|
|
dp4_pp BJ, r0, r0 // 23
|
|
|
|
// Calc A!=I
|
|
sub_pp r0, r5, r9 // 24
|
|
dp4_pp AI, r0, r0 // 25
|
|
|
|
// Calc B!=L
|
|
sub_pp r0, r6, r10 // 26
|
|
dp4_pp BL, r0, r0 // 27
|
|
|
|
// Invert register: r4 = !r4
|
|
cmp_pp r4, -r4, one, zero // 28
|
|
|
|
|
|
//
|
|
// useColB = r5.rgb =
|
|
// ((BE && BD && AI && !AF) || (BC && BF && AH)) && !AD
|
|
//
|
|
// useColA = r5.a =
|
|
// (AD && BC && BD) || (((AC && AF && BJ && !BE) || (AD && AE && BL)) && !BC)
|
|
//
|
|
// As can easily be seen, mostly the same operations need to be done for
|
|
// calculating useColA and useColB, so the following code 'might' co-issue.
|
|
// So, I'll be nice, and keep useColB in the vector pipe, and usecolA in the
|
|
// scaler pipe. It would only get rid of 5 instructions, but that is a lot if
|
|
// this is repeating hundreds of thousands of times
|
|
//
|
|
|
|
// B: BC && BF
|
|
// A: AD && AE
|
|
and_pp r6.rgb, BC, BF // 29
|
|
and_pp r6.a, AD, AE // 30
|
|
|
|
// B: (BC && BF && AH)
|
|
// A: (AD && AE && BL)
|
|
and_pp r6.rgb, r6, AH // 31
|
|
and_pp r6.a, r6, BL // 32
|
|
|
|
// B: BE && BD
|
|
// A: AC && AF
|
|
and_pp r5.rgb, BE, BD // 33
|
|
and_pp r5.a, AC, AF // 34
|
|
|
|
// B: AI && !AF
|
|
// A: BJ && !BE
|
|
cmp_pp r7.rgb, -AF, AI, zero // 35
|
|
cmp_pp r7.a, -BE, BJ, zero // 36
|
|
|
|
// B: ((BE && BD && AI && !AF) || (BC && BF && AH))
|
|
// A: ((AC && AF && BJ && !BE) || (AD && AE && BL))
|
|
and_or_pp r5 ,r5, r7, r6 // 37
|
|
|
|
// B: ((BE && BD && AI && !AF) || (BC && BF && AH)) && !AD
|
|
// A: (((AC && AF && BJ && !BE) || (AD && AE && BL)) && !BC)
|
|
cmp_pp r5.rgb, -AD, r5, zero // 38
|
|
cmp_pp r5.a, -BC, r5, zero // 39
|
|
|
|
// A: AD && BC
|
|
and_pp r6.a, AD, BC // 40
|
|
|
|
// A: (AD && BC && BD) || (((AC && AF && BJ && !BE) || (AD && AE && BL)) && !BC)
|
|
and_or_pp r5.a, r6.a, BD, r5.a // 41
|
|
|
|
//
|
|
// We return ret_B, if only useColB is set.
|
|
// We return ret_A, if useColA is set.
|
|
// We return zero, if neither is set.
|
|
//
|
|
|
|
mul_pp r5.rgb, r5, ret_B // 42
|
|
cmp_pp r5, -r5.a, r5.b, ret_A // 43
|
|
mov_pp oC0, r5 // 44
|
|
|
|
#undef AC
|
|
#undef BC
|
|
#undef AD
|
|
#undef BD
|
|
#undef AE
|
|
#undef BE
|
|
#undef AF
|
|
#undef BF
|
|
#undef AH
|
|
#undef BJ
|
|
#undef AI
|
|
#undef BL
|
|
#undef one
|
|
#undef zero
|
|
#undef ret_A
|
|
#undef ret_B
|
|
#undef TexelSize
|
|
#undef or
|
|
#undef and
|
|
#undef and_or
|
|
#undef or_pp
|
|
#undef and_pp
|
|
#undef and_or_pp
|
|
};
|
|
|
|
|
|
//
|
|
// Calcuating product2 is quite complex. This function does basic calculations
|
|
// to see if r is required, and if not, then what should be done instead
|
|
//
|
|
half4 PS_Product2_Pass0 ( in VS_OUTPUT_PRODUCT2_PASS0 input ) : COLOR
|
|
{
|
|
half4 colorA = tex2D(SourceSampler, input.colorA);
|
|
half4 colorB = tex2D(SourceSampler, input.colorB);
|
|
half4 colorC = tex2D(SourceSampler, input.colorC);
|
|
half4 colorD = tex2D(SourceSampler, input.colorD);
|
|
|
|
bool AD = all(colorA == colorD);
|
|
bool BC = all(colorB == colorC);
|
|
bool AB = all(colorA == colorB);
|
|
|
|
half4 ret = 0; // Q
|
|
if (AD && !BC) ret += 1.0; // A
|
|
if (BC && !AD) ret += 0.3; // B
|
|
if (AD && BC)
|
|
{
|
|
ret = 0.6; // R
|
|
if (AB) ret = 1.0; // A
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
//
|
|
// Modified GetResult code (see normal 2xSaI code for original).
|
|
//
|
|
// Difference is so we end up outputting a number in the range 0 to 1
|
|
// instead of -4 to +4 like normal 2xSaI code calculates. Each GetResult
|
|
// function outputs a number from 0 to 0.25. These are all added together
|
|
//
|
|
inline half GetResult1(half4 A, half4 B, half4 C, half4 D)
|
|
{
|
|
half x = 0;
|
|
half y = 0;
|
|
half r = 0.125;
|
|
|
|
bool AC = all(A==C);
|
|
bool AD = all(A==D);
|
|
bool BC = all(B==C);
|
|
bool BD = all(B==D);
|
|
|
|
x = AC;
|
|
x += AD;
|
|
y = BC && !AC;
|
|
y += BD && !AD;
|
|
|
|
if (x < 1.5) r+=0.125;
|
|
if (y < 1.5) r-=0.125;
|
|
return r;
|
|
}
|
|
|
|
//
|
|
// Same as above, except returns -r
|
|
//
|
|
inline half GetResult2(half4 A, half4 B, half4 C, half4 D)
|
|
{
|
|
half x = 0;
|
|
half y = 0;
|
|
half r = 0.125;
|
|
|
|
bool AC = all(A==C);
|
|
bool AD = all(A==D);
|
|
bool BC = all(B==C);
|
|
bool BD = all(B==D);
|
|
|
|
x = AC;
|
|
x += AD;
|
|
y = BC && !AC;
|
|
y += BD && !AD;
|
|
|
|
if (x < 1.5) r-=0.125;
|
|
if (y < 1.5) r+=0.125;
|
|
return r;
|
|
}
|
|
|
|
//
|
|
// We calculate 'r' in 2 passes. This is the first pass.
|
|
//
|
|
// Both passes output a number from 0 to 0.5. Additive blending is used
|
|
// for the second pass, creating a number in the 0 to 1 range
|
|
//
|
|
half4 PS_Product2_Pass1 ( in VS_OUTPUT_PRODUCT2_PASS1 input ) : COLOR
|
|
{
|
|
half4 colorA = tex2D(SourceSampler, input.colorA);
|
|
half4 colorB = tex2D(SourceSampler, input.colorB);
|
|
half4 colorG = tex2D(SourceSampler, input.colorG);
|
|
half4 colorE = tex2D(SourceSampler, input.colorE);
|
|
half4 colorK = tex2D(SourceSampler, input.colorK);
|
|
half4 colorF = tex2D(SourceSampler, input.colorF);
|
|
|
|
half r = 0;
|
|
r += GetResult1 (colorA, colorB, colorG, colorE);
|
|
r += GetResult2 (colorB, colorA, colorK, colorF);
|
|
|
|
return r;
|
|
}
|
|
|
|
//
|
|
// and this is the second pass
|
|
//
|
|
half4 PS_Product2_Pass2 ( in VS_OUTPUT_PRODUCT2_PASS2 input ) : COLOR
|
|
{
|
|
half4 colorA = tex2D(SourceSampler, input.colorA);
|
|
half4 colorB = tex2D(SourceSampler, input.colorB);
|
|
half4 colorL = tex2D(SourceSampler, input.colorL);
|
|
half4 colorO = tex2D(SourceSampler, input.colorO);
|
|
half4 colorH = tex2D(SourceSampler, input.colorH);
|
|
half4 colorN = tex2D(SourceSampler, input.colorN);
|
|
|
|
half r = 0;
|
|
r += GetResult2 (colorB, colorA, colorH, colorN);
|
|
r += GetResult1 (colorA, colorB, colorL, colorO);
|
|
|
|
return r;
|
|
}
|
|
|
|
//
|
|
// Final combine stage. Outputs to framebuffer.
|
|
//
|
|
// Uses preprocess information, and information about what pixel to output
|
|
// to to various interpolations of the colours where required.
|
|
//
|
|
half4 PS_Combine ( in VS_OUTPUT_COMBINE input ) : COLOR
|
|
{
|
|
half4 selector = tex2D(ModuloSampler, input.Selector);
|
|
half4 working = tex2D(WorkingSampler, input.colorA);
|
|
half4 colorA = tex2D(SRGBSourceSampler, input.colorA);
|
|
half4 colorB = tex2D(SRGBSourceSampler, input.colorB);
|
|
half4 colorC = tex2D(SRGBSourceSampler, input.colorC);
|
|
half4 colorD = tex2D(SRGBSourceSampler, input.colorD);
|
|
half4 ABCD = (colorA+colorB+colorC+colorD)/4;
|
|
|
|
half4 product0 = colorA;
|
|
if (working.r < 0.6) product0 = colorB;
|
|
if (working.r < 0.3) product0 = (colorA+colorB)/2;
|
|
|
|
half4 product1 = colorA;
|
|
if (working.g < 0.6) product1 = colorC;
|
|
if (working.g < 0.3) product1 = (colorA+colorC)/2;
|
|
|
|
bool AD = all(colorA == colorD);
|
|
bool BC = all(colorB == colorC);
|
|
bool AB = all(colorA == colorB);
|
|
|
|
half4 product2 = ABCD;
|
|
if (working.a > 0.55) product2 = colorA;
|
|
if (working.a < 0.45) product2 = colorB;
|
|
if (working.b < 0.5) product2 = colorB;
|
|
if (working.b < 0.25) product2 = ABCD;
|
|
if (working.b > 0.75) product2 = colorA;
|
|
|
|
half4 ret = colorA;
|
|
if (selector.x >= 0.5) ret = product0;
|
|
if (selector.y >= 0.5) ret = product1;
|
|
if (selector.x >= 0.5 && selector.y >= 0.5) ret = product2;
|
|
|
|
return ret;
|
|
}
|
|
|
|
technique Preprocess_2xSaI
|
|
{
|
|
pass prod0
|
|
{
|
|
// shaders
|
|
VertexShader = compile vs_1_1 VS_Product0();
|
|
PixelShader = (PS_Product0_1);
|
|
|
|
Sampler[0] = (SourceSampler);
|
|
PixelShaderConstant[2] = (TexelSize);
|
|
AlphaBlendEnable = FALSE;
|
|
ColorWriteEnable = RED;
|
|
SRGBWRITEENABLE = FALSE;
|
|
}
|
|
pass prod1
|
|
{
|
|
// shaders
|
|
VertexShader = compile vs_1_1 VS_Product1();
|
|
PixelShader = (PS_Product0_1);
|
|
|
|
Sampler[0] = (SourceSampler);
|
|
PixelShaderConstant[2] = (TexelSize);
|
|
AlphaBlendEnable = FALSE;
|
|
ColorWriteEnable = GREEN;
|
|
SRGBWRITEENABLE = FALSE;
|
|
}
|
|
pass prod2_pass0
|
|
{
|
|
// shaders
|
|
VertexShader = compile vs_1_1 VS_Product2_Pass0();
|
|
PixelShader = compile ps_2_0 PS_Product2_Pass0();
|
|
ColorWriteEnable = BLUE;
|
|
AlphaBlendEnable = FALSE;
|
|
SRGBWRITEENABLE = FALSE;
|
|
}
|
|
pass prod2_pass1
|
|
{
|
|
// shaders
|
|
VertexShader = compile vs_1_1 VS_Product2_Pass1();
|
|
PixelShader = compile ps_2_0 PS_Product2_Pass1();
|
|
ColorWriteEnable = ALPHA;
|
|
AlphaBlendEnable = FALSE;
|
|
SRGBWRITEENABLE = FALSE;
|
|
}
|
|
pass prod2_pass2
|
|
{
|
|
// shaders
|
|
VertexShader = compile vs_1_1 VS_Product2_Pass2();
|
|
PixelShader = compile ps_2_0 PS_Product2_Pass2();
|
|
ColorWriteEnable = ALPHA;
|
|
AlphaBlendEnable = TRUE;
|
|
SrcBlend = ONE;
|
|
DestBlend = ONE;
|
|
SRGBWRITEENABLE = FALSE;
|
|
}
|
|
}
|
|
|
|
technique Combine_2xSaI
|
|
{
|
|
pass P0
|
|
{
|
|
// shaders
|
|
VertexShader = compile vs_1_1 VS_Combine();
|
|
PixelShader = compile ps_2_0 PS_Combine();
|
|
AlphaBlendEnable = FALSE;
|
|
ColorWriteEnable = RED|GREEN|BLUE|ALPHA;
|
|
SRGBWRITEENABLE = TRUE;
|
|
}
|
|
}
|