port from perforce
This commit is contained in:
352
intromat/Intromat/ViewModels/ShaderFileViewModel.cs
Normal file
352
intromat/Intromat/ViewModels/ShaderFileViewModel.cs
Normal file
@@ -0,0 +1,352 @@
|
||||
using Intromat.Views;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace Intromat.ViewModels
|
||||
{
|
||||
public sealed class ShaderFileViewModel : FileViewModel
|
||||
{
|
||||
private string _source = string.Empty;
|
||||
|
||||
static ShaderFileViewModel()
|
||||
{
|
||||
Locator.CurrentMutable.Register(() => new ShaderFileView(), typeof(IViewFor<ShaderFileViewModel>));
|
||||
}
|
||||
|
||||
public ShaderFileViewModel(MainViewModel mainVm, ModuleViewModel module, FolderViewModel parent, string name)
|
||||
: base(module, parent, name, "hlsl")
|
||||
{
|
||||
}
|
||||
|
||||
public static ShaderFileViewModel CreateDefault(MainViewModel mainVm, ModuleViewModel module, FolderViewModel parent, string name)
|
||||
{
|
||||
var shaderVm = new ShaderFileViewModel(mainVm, module, parent, name);
|
||||
shaderVm.Source = @"
|
||||
// Pixel UberShader
|
||||
int idot(int3 x, int3 y)
|
||||
{
|
||||
int3 tmp = x * y;
|
||||
return tmp.x + tmp.y + tmp.z;
|
||||
}
|
||||
int idot(int4 x, int4 y)
|
||||
{
|
||||
int4 tmp = x * y;
|
||||
return tmp.x + tmp.y + tmp.z + tmp.w;
|
||||
}
|
||||
|
||||
int iround(float x) { return int (round(x)); }
|
||||
int2 iround(float2 x) { return int2(round(x)); }
|
||||
int3 iround(float3 x) { return int3(round(x)); }
|
||||
int4 iround(float4 x) { return int4(round(x)); }
|
||||
|
||||
int itrunc(float x) { return int (trunc(x)); }
|
||||
int2 itrunc(float2 x) { return int2(trunc(x)); }
|
||||
int3 itrunc(float3 x) { return int3(trunc(x)); }
|
||||
int4 itrunc(float4 x) { return int4(trunc(x)); }
|
||||
|
||||
SamplerState samp[8] : register(s0);
|
||||
|
||||
Texture2DArray Tex[8] : register(t0);
|
||||
|
||||
cbuffer PSBlock : register(b0) {
|
||||
int4 color[4];
|
||||
int4 k[4];
|
||||
int4 alphaRef;
|
||||
float4 texdim[8];
|
||||
int4 czbias[2];
|
||||
int4 cindscale[2];
|
||||
int4 cindmtx[6];
|
||||
int4 cfogcolor;
|
||||
int4 cfogi;
|
||||
float4 cfogf[2];
|
||||
float4 czslope;
|
||||
float4 cefbscale;
|
||||
};
|
||||
struct VS_OUTPUT {
|
||||
float4 pos : POSITION;
|
||||
float4 colors_0 : COLOR0;
|
||||
float4 colors_1 : COLOR1;
|
||||
float3 tex[8] : TEXCOORD0;
|
||||
float4 clipPos : TEXCOORD8;
|
||||
};
|
||||
cbuffer UBERBlock : register(b4) {
|
||||
uint bpmem_genmode;
|
||||
uint bpmem_tevorder[8];
|
||||
uint2 bpmem_combiners[16];
|
||||
uint bpmem_tevksel[8];
|
||||
int4 konstLookup[32];
|
||||
float4 debug;
|
||||
};
|
||||
uint bitfieldExtract(uint val, int off, int size) {
|
||||
// This built-in function is only support in OpenGL 4.0 and ES 3.1
|
||||
// Hopefully the shader compiler will get our meaning and emit the right instruction
|
||||
uint mask = uint((1 << size) - 1);
|
||||
return uint(val >> off) & mask;
|
||||
}
|
||||
|
||||
int4 sampleTexture(uint sampler_num, float2 uv) {
|
||||
// This is messy, but DirectX, OpenGl 3.3 and Opengl ES 3.0 doesn't support dynamic indexing of the sampler array
|
||||
// With any luck the shader compiler will optimise this if the hardware supports dynamic indexing.
|
||||
switch(sampler_num & 0x7u) {
|
||||
case 0u: return int4(Tex[0].Sample(samp[0], float3(uv, 0.0)) * 255.0);
|
||||
case 1u: return int4(Tex[1].Sample(samp[1], float3(uv, 0.0)) * 255.0);
|
||||
case 2u: return int4(Tex[2].Sample(samp[2], float3(uv, 0.0)) * 255.0);
|
||||
case 3u: return int4(Tex[3].Sample(samp[3], float3(uv, 0.0)) * 255.0);
|
||||
case 4u: return int4(Tex[4].Sample(samp[4], float3(uv, 0.0)) * 255.0);
|
||||
case 5u: return int4(Tex[5].Sample(samp[5], float3(uv, 0.0)) * 255.0);
|
||||
case 6u: return int4(Tex[6].Sample(samp[6], float3(uv, 0.0)) * 255.0);
|
||||
case 7u: return int4(Tex[7].Sample(samp[7], float3(uv, 0.0)) * 255.0);
|
||||
}
|
||||
}
|
||||
|
||||
void main(
|
||||
out float4 ocol0 : SV_Target0,
|
||||
in float4 rawpos : SV_Position,
|
||||
in float4 colors_0 : COLOR0,
|
||||
in float4 colors_1 : COLOR1
|
||||
,
|
||||
in float3 tex[8] : TEXCOORD0,
|
||||
in float4 clipPos : TEXCOORD8 ) {
|
||||
int3 ColorInput[16];
|
||||
// ColorInput initial state:
|
||||
ColorInput[0] = color[0].rgb;
|
||||
ColorInput[1] = color[0].aaa;
|
||||
ColorInput[2] = color[1].rgb;
|
||||
ColorInput[3] = color[1].aaa;
|
||||
ColorInput[4] = color[2].rgb;
|
||||
ColorInput[5] = color[2].aaa;
|
||||
ColorInput[6] = color[3].rgb;
|
||||
ColorInput[7] = color[3].aaa;
|
||||
ColorInput[8] = int3(0, 0, 0); // TexColor.rgb (uninitilized)
|
||||
ColorInput[9] = int3(0, 0, 0); // TexColor.aaa (uninitilized)
|
||||
ColorInput[10] = int3(0, 0, 0); // RasColor.rgb (uninitilized)
|
||||
ColorInput[11] = int3(0, 0, 0); // RasColor.aaa (uninitilized)
|
||||
ColorInput[12] = int3(255, 255, 255); // One constant
|
||||
ColorInput[13] = int3(128, 128, 128); // Half constant
|
||||
ColorInput[14] = int3(0, 0, 0); // KonstColor.rgb (unititilized)
|
||||
ColorInput[15] = int3(0, 0, 0); // Zero constant
|
||||
|
||||
int AlphaInput[8];
|
||||
// AlphaInput's intial state:
|
||||
AlphaInput[0] = color[0].a;
|
||||
AlphaInput[1] = color[1].a;
|
||||
AlphaInput[2] = color[2].a;
|
||||
AlphaInput[3] = color[3].a;
|
||||
AlphaInput[4] = 0; // TexColor.a (uninitilized)
|
||||
AlphaInput[5] = 0; // RasColor.a (uninitilized)
|
||||
AlphaInput[6] = 0; // KostColor.a (uninitilized)
|
||||
AlphaInput[7] = 0; // Zero constant
|
||||
|
||||
int AlphaBump = 0;
|
||||
int4 icolors_0 = int4(colors_0 * 255.0);
|
||||
int4 icolors_1 = int4(colors_1 * 255.0);
|
||||
int4 TevResult = color[0];
|
||||
|
||||
uint num_stages = bitfieldExtract(bpmem_genmode, 10, 4);
|
||||
// Main tev loop
|
||||
[loop]
|
||||
for(uint stage = 0u; stage < num_stages; stage++)
|
||||
{
|
||||
uint cc = bpmem_combiners[stage].x;
|
||||
uint ac = bpmem_combiners[stage].y;
|
||||
uint order = bpmem_tevorder[stage>>1];
|
||||
if ((stage & 1u) == 1u)
|
||||
order = order >> 12;
|
||||
|
||||
// TODO: Indirect textures
|
||||
|
||||
// Sample texture for stage
|
||||
int4 texColor;
|
||||
if((order & 64u) != 0u) {
|
||||
// Texture is enabled
|
||||
uint sampler_num = bitfieldExtract(order, 0, 3);
|
||||
uint tex_coord = bitfieldExtract(order, 3, 3);
|
||||
|
||||
// TODO: there is an optional perspective divide here (not to mention all of indirect)
|
||||
int2 fixedPoint_uv = itrunc(tex[tex_coord].xy * texdim[sampler_num].zw * 128.0);
|
||||
float2 uv = (float2(fixedPoint_uv) / 128.0) * texdim[sampler_num].xy;
|
||||
|
||||
texColor = sampleTexture(sampler_num, uv);
|
||||
} else {
|
||||
// Texture is disabled
|
||||
texColor = int4(255, 255, 255, 255);
|
||||
}
|
||||
// TODO: color channel swapping
|
||||
ColorInput[8] = texColor.rgb;
|
||||
ColorInput[9] = texColor.aaa;
|
||||
AlphaInput[4] = texColor.a;
|
||||
|
||||
// Set Konst for stage
|
||||
uint tevksel = bpmem_tevksel[stage>>1];
|
||||
int4 konst;
|
||||
if ((stage & 1u) == 0u)
|
||||
konst = int4(konstLookup[bitfieldExtract(tevksel, 4, 5)].rgb, konstLookup[bitfieldExtract(tevksel, 9, 5)].a);
|
||||
else
|
||||
konst = int4(konstLookup[bitfieldExtract(tevksel, 14, 5)].rgb, konstLookup[bitfieldExtract(tevksel, 19, 5)].a);
|
||||
|
||||
ColorInput[14] = konst.rgb;
|
||||
AlphaInput[6] = konst.a;
|
||||
|
||||
// Set Ras for stage
|
||||
int4 ras;
|
||||
switch (bitfieldExtract(order, 7, 3)) {
|
||||
case 0u: // Color 0
|
||||
ras = icolors_0;
|
||||
break;
|
||||
case 1u: // Color 1
|
||||
ras = icolors_1;
|
||||
break;
|
||||
case 5u: // Alpha Bump
|
||||
ras = int4(AlphaBump, AlphaBump, AlphaBump, AlphaBump);
|
||||
break;
|
||||
case 6u: // Normalzied Alpha Bump
|
||||
int normalized = AlphaBump | AlphaBump >> 5;
|
||||
ras = int4(normalized, normalized, normalized, normalized);
|
||||
break;
|
||||
default:
|
||||
ras = int4(0, 0, 0, 0);
|
||||
break;
|
||||
}
|
||||
// TODO: color channel swapping
|
||||
ColorInput[10] = ras.rgb;
|
||||
ColorInput[11] = ras.aaa;
|
||||
AlphaInput[5] = ras.a;
|
||||
|
||||
// Color Combiner
|
||||
{
|
||||
uint a = bitfieldExtract(cc, 12, 4);
|
||||
uint b = bitfieldExtract(cc, 8, 4);
|
||||
uint c = bitfieldExtract(cc, 4, 4);
|
||||
uint d = bitfieldExtract(cc, 0, 4);
|
||||
uint bias = bitfieldExtract(cc, 16, 2);
|
||||
bool op = bool(bitfieldExtract(cc, 18, 1));
|
||||
bool _clamp = bool(bitfieldExtract(cc, 19, 1));
|
||||
uint shift = bitfieldExtract(cc, 20, 2);
|
||||
uint dest = bitfieldExtract(cc, 22, 2);
|
||||
|
||||
int3 A = ColorInput[a] & int3(255, 255, 255);
|
||||
int3 B = ColorInput[b] & int3(255, 255, 255);
|
||||
int3 C = ColorInput[c] & int3(255, 255, 255);
|
||||
int3 D = ColorInput[d]; // 10 bits + sign
|
||||
|
||||
int3 result;
|
||||
if(bias != 3u) { // Normal mode
|
||||
// Lerp A and B with C
|
||||
C += C >> 7; // Scale C from 0..255 to 0..256
|
||||
int3 lerp = (A << 8) + (B - A)*C;
|
||||
if (shift != 3u) {
|
||||
lerp = lerp << shift;
|
||||
lerp = lerp + (op ? 127 : 128);
|
||||
}
|
||||
result = lerp >> 8;
|
||||
|
||||
// Add/Subtract D (and bias)
|
||||
if (bias == 1u) result += 128;
|
||||
else if (bias == 2u) result -= 128;
|
||||
if(!op) // Add
|
||||
result = D + result;
|
||||
else // Subtract
|
||||
result = D - result;
|
||||
|
||||
// Most of the Shift was moved inside the lerp for improved percision
|
||||
// But we still do the divide by 2 here
|
||||
if (shift == 3u)
|
||||
result = result >> 1;
|
||||
} else { // Compare mode
|
||||
// Not implemented
|
||||
result = int3(255, 0, 0);
|
||||
}
|
||||
|
||||
// Clamp result
|
||||
if (_clamp)
|
||||
result = clamp(result, 0, 255);
|
||||
else
|
||||
result = clamp(result, -1024, 1023);
|
||||
|
||||
if (stage == num_stages) { // If this is the last stage
|
||||
// Write result to output
|
||||
TevResult.rgb = result;
|
||||
//break;
|
||||
} else {
|
||||
// Write result to the correct input register of the next stage
|
||||
ColorInput[dest<<1] = result;
|
||||
}
|
||||
}
|
||||
// Alpha Combiner
|
||||
{
|
||||
uint a = bitfieldExtract(ac, 13, 3);
|
||||
uint b = bitfieldExtract(ac, 10, 3);
|
||||
uint c = bitfieldExtract(ac, 7, 3);
|
||||
uint d = bitfieldExtract(ac, 4, 3);
|
||||
uint bias = bitfieldExtract(ac, 16, 2);
|
||||
bool op = bool(bitfieldExtract(ac, 18, 1));
|
||||
bool _clamp = bool(bitfieldExtract(ac, 19, 1));
|
||||
uint shift = bitfieldExtract(ac, 20, 2);
|
||||
uint dest = bitfieldExtract(ac, 22, 2);
|
||||
|
||||
int A = AlphaInput[a] & 255;
|
||||
int B = AlphaInput[b] & 255;
|
||||
int C = AlphaInput[c] & 255;
|
||||
int D = AlphaInput[d]; // 10 bits + sign
|
||||
|
||||
int result;
|
||||
if(bias != 3u) { // Normal mode
|
||||
// Lerp A and B with C
|
||||
C += C >> 7; // Scale C from 0..255 to 0..256
|
||||
int lerp = (A << 8) + (B - A)*C;
|
||||
if (shift != 3u) {
|
||||
lerp = lerp << shift;
|
||||
lerp = lerp + (op ? 127 : 128);
|
||||
}
|
||||
result = lerp >> 8;
|
||||
|
||||
// Add/Subtract D (and bias)
|
||||
if (bias == 1u) result += 128;
|
||||
else if (bias == 2u) result -= 128;
|
||||
if(!op) // Add
|
||||
result = D + result;
|
||||
else // Subtract
|
||||
result = D - result;
|
||||
|
||||
// Most of the Shift was moved inside the lerp for improved percision
|
||||
// But we still do the divide by 2 here
|
||||
if (shift == 3u)
|
||||
result = result >> 1;
|
||||
} else { // Compare mode
|
||||
// Not implemented
|
||||
result = 255;
|
||||
}
|
||||
|
||||
// Clamp result
|
||||
if (_clamp)
|
||||
result = clamp(result, 0, 255);
|
||||
else
|
||||
result = clamp(result, -1024, 1023);
|
||||
|
||||
if (stage == num_stages) { // If this is the last stage
|
||||
// Write result to output
|
||||
TevResult.a = result;
|
||||
} else {
|
||||
// Write result to the correct input register of the next stage
|
||||
AlphaInput[dest] = result;
|
||||
ColorInput[(dest << 1) + 1u] = int3(result, result, result);
|
||||
}
|
||||
}
|
||||
} // Main tev loop
|
||||
|
||||
ocol0 = float4(TevResult) / 255.0;
|
||||
|
||||
}
|
||||
";
|
||||
return shaderVm;
|
||||
}
|
||||
|
||||
public string Source
|
||||
{
|
||||
get => _source;
|
||||
set => this.RaiseAndSetIfChanged(ref _source, value);
|
||||
}
|
||||
|
||||
public override ReactiveObject CurrentViewModel => this;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user