diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c07f4bb..7ee76816 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -607,7 +607,7 @@ add_custom_target( ) add_custom_target( - GeneratePortOTR + GeneratePortO2R DEPENDS TorchExternal WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND ${TORCH_EXECUTABLE} pack port starship.o2r o2r diff --git a/docs/BUILDING.md b/docs/BUILDING.md index aac581e6..e6922301 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -36,6 +36,9 @@ cd starship # Generate sf64.o2r & 'C:\Program Files\CMake\bin\cmake.exe' --build .\build\x64 --target ExtractAssets +# Generate starship.o2r +& 'C:\Program Files\CMake\bin\cmake.exe' --build .\build\x64 --target GeneratePortO2R + # Compile project # Add `--config Release` if you're packaging & 'C:\Program Files\CMake\bin\cmake.exe' --build .\build\x64 @@ -133,6 +136,9 @@ cmake -H. -Bbuild-cmake -GNinja # Generate sf64.o2r cmake --build build-cmake --target ExtractAssets +# Generate starship.o2r +cmake --build build-cmake --target GeneratePortO2R + # Compile the project # Add `--config Release` if you're packaging cmake --build build-cmake @@ -180,6 +186,9 @@ cmake -H. -Bbuild-cmake -GNinja # Generate sf64.o2r cmake --build build-cmake --target ExtractAssets +# Generate starship.o2r +cmake --build build-cmake --target GeneratePortO2R + # Compile the project # Add `--config Release` if you're packaging cmake --build build-cmake diff --git a/libultraship b/libultraship index 02bb77ef..c6bd64c5 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit 02bb77ef253e2de0969fd2cb36ad2e870677d18d +Subproject commit c6bd64c5da0e55a1c00e969bc01046f9335cda43 diff --git a/port/assets/fonts/Fipps-Regular.otf b/port/assets/fonts/Fipps-Regular.otf deleted file mode 100644 index 9334dad5..00000000 Binary files a/port/assets/fonts/Fipps-Regular.otf and /dev/null differ diff --git a/port/assets/fonts/PressStart2P-Regular.ttf b/port/assets/fonts/PressStart2P-Regular.ttf deleted file mode 100644 index 2442affb..00000000 Binary files a/port/assets/fonts/PressStart2P-Regular.ttf and /dev/null differ diff --git a/port/assets/textures/buttons/ABtn.png b/port/assets/textures/buttons/ABtn.png deleted file mode 100644 index c1b06571..00000000 Binary files a/port/assets/textures/buttons/ABtn.png and /dev/null differ diff --git a/port/assets/textures/buttons/BBtn.png b/port/assets/textures/buttons/BBtn.png deleted file mode 100644 index 99b1197c..00000000 Binary files a/port/assets/textures/buttons/BBtn.png and /dev/null differ diff --git a/port/assets/textures/buttons/CDown.png b/port/assets/textures/buttons/CDown.png deleted file mode 100644 index 741188ea..00000000 Binary files a/port/assets/textures/buttons/CDown.png and /dev/null differ diff --git a/port/assets/textures/buttons/CLeft.png b/port/assets/textures/buttons/CLeft.png deleted file mode 100644 index 5e26a206..00000000 Binary files a/port/assets/textures/buttons/CLeft.png and /dev/null differ diff --git a/port/assets/textures/buttons/CRight.png b/port/assets/textures/buttons/CRight.png deleted file mode 100644 index 9e618063..00000000 Binary files a/port/assets/textures/buttons/CRight.png and /dev/null differ diff --git a/port/assets/textures/buttons/CUp.png b/port/assets/textures/buttons/CUp.png deleted file mode 100644 index 6c0e29d2..00000000 Binary files a/port/assets/textures/buttons/CUp.png and /dev/null differ diff --git a/port/assets/textures/buttons/LBtn.png b/port/assets/textures/buttons/LBtn.png deleted file mode 100644 index 2e0a8f00..00000000 Binary files a/port/assets/textures/buttons/LBtn.png and /dev/null differ diff --git a/port/assets/textures/buttons/RBtn.png b/port/assets/textures/buttons/RBtn.png deleted file mode 100644 index c255643c..00000000 Binary files a/port/assets/textures/buttons/RBtn.png and /dev/null differ diff --git a/port/assets/textures/buttons/StartBtn.png b/port/assets/textures/buttons/StartBtn.png deleted file mode 100644 index c3e08dc3..00000000 Binary files a/port/assets/textures/buttons/StartBtn.png and /dev/null differ diff --git a/port/assets/textures/buttons/ZBtn.png b/port/assets/textures/buttons/ZBtn.png deleted file mode 100644 index def8d9a6..00000000 Binary files a/port/assets/textures/buttons/ZBtn.png and /dev/null differ diff --git a/port/assets/textures/icons/gIcon.png b/port/assets/textures/icons/gIcon.png deleted file mode 100644 index 69764591..00000000 Binary files a/port/assets/textures/icons/gIcon.png and /dev/null differ diff --git a/port/assets/textures/virtual/gEmptyTexture.rgba32.png b/port/assets/textures/virtual/gEmptyTexture.rgba32.png deleted file mode 100644 index eaf806b7..00000000 Binary files a/port/assets/textures/virtual/gEmptyTexture.rgba32.png and /dev/null differ diff --git a/port/shaders/directx/default.shader.hlsl b/port/shaders/directx/default.shader.hlsl new file mode 100644 index 00000000..f36c2dae --- /dev/null +++ b/port/shaders/directx/default.shader.hlsl @@ -0,0 +1,332 @@ +@prism(type='hlsl', name='Fast3D HLSL Shader', version='1.0.0', description='Ported shader to prism', author='Emill & Prism Team') + +@if(o_root_signature) + @if(o_textures[0]) + #define RS "RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | DENY_VERTEX_SHADER_ROOT_ACCESS), CBV(b0, visibility = SHADER_VISIBILITY_PIXEL), DescriptorTable(SRV(t0), visibility = SHADER_VISIBILITY_PIXEL), DescriptorTable(Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL)" + @end + @if(o_textures[1]) + #define RS "RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | DENY_VERTEX_SHADER_ROOT_ACCESS), CBV(b0, visibility = SHADER_VISIBILITY_PIXEL), DescriptorTable(SRV(t1), visibility = SHADER_VISIBILITY_PIXEL), DescriptorTable(Sampler(s1), visibility = SHADER_VISIBILITY_PIXEL)" + @end +@end + +struct PSInput { + float4 position : SV_POSITION; +@for(i in 0..2) + @if(o_textures[i]) + float2 uv@{i} : TEXCOORD@{i}; + @{update_floats(2)} + @for(j in 0..2) + @if(o_clamp[i][j]) + @if(j == 0) + float texClampS@{i} : TEXCLAMPS@{i}; + @else + float texClampT@{i} : TEXCLAMPT@{i}; + @end + @{update_floats(1)} + @end + @end + @end +@end + +@if(o_fog) +float4 fog : FOG; +@{update_floats(4)} +@end +@if(o_grayscale) +float4 grayscale : GRAYSCALE; +@{update_floats(4)} +@end + +@for(i in 0..o_inputs) + @if(o_alpha) + float4 input@{i + 1} : INPUT@{i}; + @{update_floats(4)} + @else + float3 input@{i + 1} : INPUT@{i}; + @{update_floats(3)} + @end +@end +}; + +@if(o_textures[0]) + Texture2D g_texture0 : register(t0); + SamplerState g_sampler0 : register(s0); +@end +@if(o_textures[1]) + Texture2D g_texture1 : register(t1); + SamplerState g_sampler1 : register(s1); +@end + +@if(o_masks[0]) Texture2D g_textureMask0 : register(t2); +@if(o_masks[1]) Texture2D g_textureMask1 : register(t3); + +@if(o_blend[0]) Texture2D g_textureBlend0 : register(t4); +@if(o_blend[1]) Texture2D g_textureBlend1 : register(t5); + +cbuffer PerFrameCB : register(b0) { + uint noise_frame; + float noise_scale; +} + +float random(in float3 value) { + float random = dot(value, float3(12.9898, 78.233, 37.719)); + return frac(sin(random) * 143758.5453); +} + +// 3 point texture filtering +// Original author: ArthurCarvalho +// Based on GLSL implementation by twinaphex, mupen64plus-libretro project. + +@if(o_three_point_filtering && o_textures[0] || o_textures[1]) +cbuffer PerDrawCB : register(b1) { + struct { + uint width; + uint height; + bool linear_filtering; + } textures[2]; +} + +#define TEX_OFFSET(tex, tSampler, texCoord, off, texSize) tex.Sample(tSampler, texCoord - off / texSize) + +float4 tex2D3PointFilter(in Texture2D tex, in SamplerState tSampler, in float2 texCoord, in float2 texSize) { + float2 offset = frac(texCoord * texSize - float2(0.5, 0.5)); + offset -= step(1.0, offset.x + offset.y); + float4 c0 = TEX_OFFSET(tex, tSampler, texCoord, offset, texSize); + float4 c1 = TEX_OFFSET(tex, tSampler, texCoord, float2(offset.x - sign(offset.x), offset.y), texSize); + float4 c2 = TEX_OFFSET(tex, tSampler, texCoord, float2(offset.x, offset.y - sign(offset.y)), texSize); + return c0 + abs(offset.x)*(c1-c0) + abs(offset.y)*(c2-c0); +} +@end + +PSInput VSMain( + float4 position : POSITION +@for(i in 0..2) + @if(o_textures[i]) + , float2 uv@{i} : TEXCOORD@{i} + @end + @for(j in 0..2) + @if(o_clamp[i][j]) + @if(j == 0) + , float texClampS@{i} : TEXCLAMPS@{i} + @else + , float texClampT@{i} : TEXCLAMPT@{i} + @end + @end + @end +@end +@if(o_fog) + , float4 fog : FOG +@end +@if(o_grayscale) + , float4 grayscale : GRAYSCALE +@end +@for(i in 0..o_inputs) + @if(o_alpha) + , float4 input@{i + 1} : INPUT@{i} + @else + , float3 input@{i + 1} : INPUT@{i} + @end +@end +) { + PSInput result; + result.position = position; + @for(i in 0..2) + @if(o_textures[i]) + result.uv@{i} = uv@{i}; + @for(j in 0..2) + @if(o_clamp[i][j]) + @if(j == 0) + result.texClampS@{i} = texClampS@{i}; + @else + result.texClampT@{i} = texClampT@{i}; + @end + @end + @end + @end + @end + + @if(o_fog) + result.fog = fog; + @end + + @if(o_grayscale) + result.grayscale = grayscale; + @end + + @for(i in 0..o_inputs) + @if(o_alpha) + result.input@{i + 1} = input@{i + 1}; + @else + result.input@{i + 1} = float4(input@{i + 1}, 1.0); + @end + @end + + return result; +} + +@if(o_root_signature) + [RootSignature(RS)] +@end + +@if(srgb_mode) + float4 fromLinear(float4 linearRGB){ + bool3 cutoff = linearRGB.rgb < float3(0.0031308, 0.0031308, 0.0031308); + float3 higher = 1.055 * pow(linearRGB.rgb, float3(1.0 / 2.4, 1.0 / 2.4, 1.0 / 2.4)) - float3(0.055, 0.055, 0.055); + float3 lower = linearRGB.rgb * float3(12.92, 12.92, 12.92); + return float4(lerp(higher, lower, cutoff), linearRGB.a); + } +@end + +#define MOD(x, y) ((x) - (y) * floor((x)/(y))) +#define WRAP(x, low, high) MOD((x)-(low), (high)-(low)) + (low) + +float4 PSMain(PSInput input, float4 screenSpace : SV_Position) : SV_TARGET { + @for(i in 0..2) + @if(o_textures[i]) + float2 tc@{i} = input.uv@{i}; + @{s = o_clamp[i][0]} + @{t = o_clamp[i][1]} + @if(s && t) + int2 texSize@{i}; + g_texture@{i}.GetDimensions(texSize@{i}.x, texSize@{i}.y); + @if(s && t) + tc@{i} = clamp(tc@{i}, 0.5 / texSize@{i}, float2(input.texClampS@{i}, input.texClampT@{i})); + @elseif(s) + tc@{i} = float2(clamp(tc@{i}.x, 0.5 / texSize@{i}.x, input.texClampS@{i}), tc@{i}.y); + @else + tc@{i} = float2(tc@{i}.x, clamp(tc@{i}.y, 0.5 / texSize@{i}.y, input.texClampT@{i})); + @end + @end + + @if(o_three_point_filtering) + float4 texVal@{i}; + if (textures[@{i}].linear_filtering) { + @if(o_masks[i]) + texVal@{i} = tex2D3PointFilter(g_texture@{i}, g_sampler@{i}, tc@{i}, float2(textures[@{i}].width, textures[@{i}].height)); + float2 maskSize@{i}; + g_textureMask@{i}.GetDimensions(maskSize@{i}.x, maskSize@{i}.y); + float4 maskVal@{i} = tex2D3PointFilter(g_textureMask@{i}, g_sampler@{i}, tc@{i}, maskSize@{i}); + @if(o_blend[i]) + float4 blendVal@{i} = tex2D3PointFilter(g_textureBlend@{i}, g_sampler@{i}, tc@{i}, float2(textures[@{i}].width, textures[@{i}].height)); + @else + float4 blendVal@{i} = float4(0, 0, 0, 0); + @end + + texVal@{i} = lerp(texVal@{i}, blendVal@{i}, maskVal@{i}.a); + @else + texVal@{i} = tex2D3PointFilter(g_texture@{i}, g_sampler@{i}, tc@{i}, float2(textures[@{i}].width, textures[@{i}].height)); + @end + } else { + texVal@{i} = g_texture@{i}.Sample(g_sampler@{i}, tc@{i}); + @if(o_masks[i]) + @if(o_blend[i]) + float4 blendVal@{i} = g_textureBlend@{i}.Sample(g_sampler@{i}, tc@{i}); + @else + float4 blendVal@{i} = float4(0, 0, 0, 0); + @end + texval@{i} = lerp(texVal@{i}, blendVal@{i}, g_textureMask@{i}.Sample(g_sampler@{i}, tc@{i}).a); + @end + } + @else + float4 texVal@{i} = g_texture@{i}.Sample(g_sampler@{i}, tc@{i}); + @if(o_masks[i]) + @if(o_blend[i]) + float4 blendVal@{i} = g_textureBlend@{i}.Sample(g_sampler@{i}, tc@{i}); + @else + float4 blendVal@{i} = float4(0, 0, 0, 0); + @end + texVal@{i} = lerp(texVal@{i}, blendVal@{i}, g_textureMask@{i}.Sample(g_sampler@{i}, tc@{i}).a); + @end + @end + @end + @end + + @if(o_alpha) + float4 texel; + @else + float3 texel; + @end + + @if(o_2cyc) + @{f_range = 2} + @else + @{f_range = 1} + @end + + @for(c in 0..f_range) + @if(c == 1) + @if(o_alpha) + @if(o_c[c][1][2] == SHADER_COMBINED) + texel.a = WRAP(texel.a, -1.01, 1.01); + @else + texel.a = WRAP(texel.a, -0.51, 1.51); + @end + @end + + @if(o_c[c][0][2] == SHADER_COMBINED) + texel.rgb = WRAP(texel.rgb, -1.01, 1.01); + @else + texel.rgb = WRAP(texel.rgb, -0.51, 1.51); + @end + @end + + @if(!o_color_alpha_same[c] && o_alpha) + texel = float4(@{ + append_formula(o_c[c], o_do_single[c][0], + o_do_multiply[c][0], o_do_mix[c][0], false, false, true, c == 0) + }, @{append_formula(o_c[c], o_do_single[c][1], + o_do_multiply[c][1], o_do_mix[c][1], true, true, true, c == 0) + }); + @else + texel = @{append_formula(o_c[c], o_do_single[c][0], + o_do_multiply[c][0], o_do_mix[c][0], o_alpha, false, + o_alpha, c == 0)}; + @end + @end + + @if(o_texture_edge && o_alpha) + if (texel.a > 0.19) texel.a = 1.0; else discard; + @end + + texel = WRAP(texel, -0.51, 1.51); + texel = clamp(texel, 0.0, 1.0); + // TODO discard if alpha is 0? + @if(o_fog) + @if(o_alpha) + texel = float4(lerp(texel.rgb, input.fog.rgb, input.fog.a), texel.a); + @else + texel = lerp(texel, input.fog.rgb, input.fog.a); + @end + @end + + @if(o_grayscale) + float intensity = (texel.r + texel.g + texel.b) / 3.0; + float3 new_texel = input.grayscale.rgb * intensity; + texel.rgb = lerp(texel.rgb, new_texel, input.grayscale.a); + @end + + @if(o_alpha && o_noise) + float2 coords = screenSpace.xy * noise_scale; + texel.a *= round(saturate(random(float3(floor(coords), noise_frame)) + texel.a - 0.5)); + @end + + @if(o_alpha) + @if(o_alpha_threshold) + if (texel.a < 8.0 / 256.0) discard; + @end + @if(o_invisible) + texel.a = 0.0; + @end + @if(srgb_mode) + return fromLinear(texel); + @else + return texel; + @end + @else + @if(srgb_mode) + return fromLinear(float4(texel, 1.0)); + @else + return float4(texel, 1.0); + @end + @end +} \ No newline at end of file diff --git a/port/shaders/metal/default.shader.metal b/port/shaders/metal/default.shader.metal new file mode 100644 index 00000000..a771ba10 --- /dev/null +++ b/port/shaders/metal/default.shader.metal @@ -0,0 +1,284 @@ +@prism(type='metal', name='Fast3D Metal Shader', version='1.0.0', description='Ported shader to prism', author='Emill & Prism Team') + +#include +using namespace metal; + +// BEGIN VERTEX SHADER +struct FrameUniforms { + int frameCount; + float noiseScale; +}; + +struct Vertex { + float4 position [[attribute(@{get_vertex_index()})]]; + @{update_floats(4)} + @for(i in 0..2) + @if(o_textures[i]) + float2 texCoord@{i} [[attribute(@{get_vertex_index()})]]; + @{update_floats(2)} + @for(j in 0..2) + @if(o_clamp[i][j]) + @if(j == 0) + float texClampS@{i} [[attribute(@{get_vertex_index()})]]; + @else + float texClampT@{i} [[attribute(@{get_vertex_index()})]]; + @end + @{update_floats(1)} + @end + @end + @end + @end + @if(o_fog) + float4 fog [[attribute(@{get_vertex_index()})]]; + @{update_floats(4)} + @end + @if(o_grayscale) + float4 grayscale [[attribute(@{get_vertex_index()})]]; + @{update_floats(4)} + @end + @for(i in 0..o_inputs) + @if(o_alpha) + float4 input@{i + 1} [[attribute(@{get_vertex_index()})]]; + @{update_floats(4)} + @else + float3 input@{i + 1} [[attribute(@{get_vertex_index()})]]; + @{update_floats(3)} + @end + @end +}; + +struct ProjectedVertex { + @for(i in 0..2) + @if(o_textures[i]) + float2 texCoord@{i}; + @for(j in 0..2) + @if(o_clamp[i][j]) + @if(j == 0) + float texClampS@{i}; + @else + float texClampT@{i}; + @end + @end + @end + @end + @end + @if(o_fog) + float4 fog; + @end + @if(o_grayscale) + float4 grayscale; + @end + @for(i in 0..o_inputs) + @if(o_alpha) + float4 input@{i + 1}; + @else + float3 input@{i + 1}; + @end + @end + float4 position [[position]]; +}; + +vertex ProjectedVertex vertexShader(Vertex in [[stage_in]]) { + ProjectedVertex out; + @for(i in 0..2) + @if(o_textures[i]) + out.texCoord@{i} = in.texCoord@{i}; + @for(j in 0..2) + @if(o_clamp[i][j]) + @if(j == 0) + out.texClampS@{i} = in.texClampS@{i}; + @else + out.texClampT@{i} = in.texClampT@{i}; + @end + @end + @end + @end + @end + @if(o_fog) + out.fog = in.fog; + @end + @if(o_grayscale) + out.grayscale = in.grayscale; + @end + @for(i in 0..o_inputs) + out.input@{i + 1} = in.input@{i + 1}; + @end + out.position = in.position; + return out; +} +// END - BEGIN FRAGMENT SHADER + +float mod(float x, float y) { + return float(x - y * floor(x / y)); +} + +float3 mod(float3 a, float3 b) { + return float3(a.x - b.x * floor(a.x / b.x), a.y - b.y * floor(a.y / b.y), a.z - b.z * floor(a.z / b.z)); +} + +float4 mod(float4 a, float4 b) { + return float4(a.x - b.x * floor(a.x / b.x), a.y - b.y * floor(a.y / b.y), a.z - b.z * floor(a.z / b.z), a.w - b.w * floor(a.w / b.w)); +} + +#define WRAP(x, low, high) mod((x)-(low), (high)-(low)) + (low) +#define TEX_OFFSET(tex, texSmplr, texCoord, off, texSize) tex.sample(texSmplr, texCoord - off / texSize) + +@if(o_three_point_filtering) + float4 filter3point(thread const texture2d tex, thread const sampler texSmplr, thread const float2& texCoord, thread const float2& texSize) { + float2 offset = fract((texCoord * texSize) - float2(0.5)); + offset -= float2(step(1.0, offset.x + offset.y)); + float4 c0 = TEX_OFFSET(tex, texSmplr, texCoord, offset, texSize); + float4 c1 = TEX_OFFSET(tex, texSmplr, texCoord, float2(offset.x - sign(offset.x), offset.y), texSize); + float4 c2 = TEX_OFFSET(tex, texSmplr, texCoord, float2(offset.x, offset.y - sign(offset.y)), texSize); + return c0 + abs(offset.x) * (c1 - c0) + abs(offset.y) * (c2 - c0); + } + + float4 hookTexture2D(thread const texture2d tex, thread const sampler texSmplr, thread const float2& uv, thread const float2& texSize) { + return filter3point(tex, texSmplr, uv, texSize); + } +@else + float4 hookTexture2D(thread const texture2d tex, thread const sampler texSmplr, thread const float2& uv, thread const float2& texSize) { + return tex.sample(texSmplr, uv); + } +@end + +float random(float3 value) { + float random = dot(sin(value), float3(12.9898, 78.233, 37.719)); + return fract(sin(random) * 143758.5453); +} + +fragment float4 fragmentShader(ProjectedVertex in [[stage_in]], constant FrameUniforms &frameUniforms [[buffer(0)]] +@if(o_textures[0]) + , texture2d uTex0 [[texture(0)]], sampler uTex0Smplr [[sampler(0)]] +@end +@if(o_textures[1]) + , texture2d uTex1 [[texture(1)]], sampler uTex1Smplr [[sampler(1)]] +@end +@if(o_masks[0]) + , texture2d uTexMask0 [[texture(2)]] +@end +@if(o_masks[1]) + , texture2d uTexMask1 [[texture(3)]] +@end +@if(o_blend[0]) + , texture2d uTexBlend0 [[texture(4)]] +@end +@if(o_blend[1]) + , texture2d uTexBlend1 [[texture(5)]] +@end +) { + @for(i in 0..2) + @if(o_textures[i]) + @{s = o_clamp[i][0]} + @{t = o_clamp[i][1]} + float2 texSize@{i} = float2(uTex@{i}.get_width(), uTex@{i}.get_height()); + @if(!s && !t) + float2 vTexCoordAdj@{i} = in.texCoord@{i}; + @else + @if(s && t) + float2 vTexCoordAdj@{i} = fast::clamp(in.texCoord@{i}, float2(0.5) / texSize@{i}, float2(in.texClampS@{i}, in.texClampT@{i})); + @elseif(s) + float2 vTexCoordAdj@{i} = float2(fast::clamp(in.texCoord@{i}.x, 0.5 / texSize@{i}.x, in.texClampS@{i}), in.texCoord@{i}.y); + @else + float2 vTexCoordAdj@{i} = float2(in.texCoord@{i}.x, fast::clamp(in.texCoord@{i}.y, 0.5 / texSize@{i}.y, in.texClampT@{i})); + @end + @end + + float4 texVal@{i} = hookTexture2D(uTex@{i}, uTex@{i}Smplr, vTexCoordAdj@{i}, texSize@{i}); + + @if(o_masks[i]) + float2 maskSize@{i} = float2(uTexMask@{i}.get_width(), uTexMask@{i}.get_height()); + float4 maskVal@{i} = hookTexture2D(uTexMask@{i}, uTex@{i}Smplr, vTexCoordAdj@{i}, maskSize@{i}); + @if(o_blend[i]) + float4 blendVal@{i} = hookTexture2D(uTexBlend@{i}, uTex@{i}Smplr, vTexCoordAdj@{i}, texSize@{i}); + @else + float4 blendVal@{i} = float4(0, 0, 0, 0); + @end + + texVal@{i} = mix(texVal@{i}, blendVal@{i}, maskVal@{i}.w); + @end + @end + @end + + @if(o_alpha) + float4 texel; + @else + float3 texel; + @end + + @if(o_2cyc) + @{f_range = 2} + @else + @{f_range = 1} + @end + + @for(c in 0..f_range) + @if(c == 1) + @if(o_alpha) + @if(o_c[c][1][2] == SHADER_COMBINED) + texel.w = WRAP(texel.w, -1.01, 1.01); + @else + texel.w = WRAP(texel.w, -0.51, 1.51); + @end + @end + + @if(o_c[c][0][2] == SHADER_COMBINED) + texel.xyz = WRAP(texel.xyz, -1.01, 1.01); + @else + texel.xyz = WRAP(texel.xyz, -0.51, 1.51); + @end + @end + + @if(!o_color_alpha_same[c] && o_alpha) + texel = float4(@{ + append_formula(o_c[c], o_do_single[c][0], + o_do_multiply[c][0], o_do_mix[c][0], false, false, true, c == 0) + }, @{append_formula(o_c[c], o_do_single[c][1], + o_do_multiply[c][1], o_do_mix[c][1], true, true, true, c == 0) + }); + @else + texel = @{append_formula(o_c[c], o_do_single[c][0], + o_do_multiply[c][0], o_do_mix[c][0], o_alpha, false, + o_alpha, c == 0)}; + @end + @end + + @if(o_texture_edge && o_alpha) + if (texel.w > 0.19) texel.w = 1.0; else discard_fragment(); + @end + + texel = WRAP(texel, -0.51, 1.51); + texel = clamp(texel, 0.0, 1.0); + // TODO discard if alpha is 0? + + @if(o_fog) + @if(o_alpha) + texel = float4(mix(texel.xyz, in.fog.xyz, in.fog.w), texel.w); + @else + texel = mix(texel, in.fog.xyz, in.fog.w); + @end + @end + + @if(o_grayscale) + float intensity = (texel.x + texel.y + texel.z) / 3.0; + float3 new_texel = in.grayscale.xyz * intensity; + texel.xyz = mix(texel.xyz, new_texel, in.grayscale.w); + @end + + @if(o_alpha && o_noise) + float2 coords = screenSpace.xy * noise_scale; + texel.w *= round(saturate(random(float3(floor(coords), noise_frame)) + texel.w - 0.5)); + @end + + @if(o_alpha) + @if(o_alpha_threshold) + if (texel.w < 8.0 / 256.0) discard_fragment(); + @end + @if(o_invisible) + texel.w = 0.0; + @end + return texel; + @else + return float4(texel, 1.0); + @end +} \ No newline at end of file diff --git a/port/shaders/opengl/default.shader.fs b/port/shaders/opengl/default.shader.fs new file mode 100644 index 00000000..b15e1598 --- /dev/null +++ b/port/shaders/opengl/default.shader.fs @@ -0,0 +1,210 @@ +@prism(type='fragment', name='Fast3D Fragment Shader', version='1.0.0', description='Ported shader to prism', author='Emill & Prism Team') + +@{GLSL_VERSION} + +@if(core_opengl || opengles) +out vec4 vOutColor; +@end + +@for(i in 0..2) + @if(o_textures[i]) + @{attr} vec2 vTexCoord@{i}; + @for(j in 0..2) + @if(o_clamp[i][j]) + @if(j == 0) + @{attr} float vTexClampS@{i}; + @else + @{attr} float vTexClampT@{i}; + @end + @end + @end + @end +@end + +@if(o_fog) @{attr} vec4 vFog; +@if(o_grayscale) @{attr} vec4 vGrayscaleColor; + +@for(i in 0..o_inputs) + @if(o_alpha) + @{attr} vec4 vInput@{i + 1}; + @else + @{attr} vec3 vInput@{i + 1}; + @end +@end + +@if(o_textures[0]) uniform sampler2D uTex0; +@if(o_textures[1]) uniform sampler2D uTex1; + +@if(o_masks[0]) uniform sampler2D uTexMask0; +@if(o_masks[1]) uniform sampler2D uTexMask1; + +@if(o_blend[0]) uniform sampler2D uTexBlend0; +@if(o_blend[1]) uniform sampler2D uTexBlend1; + +uniform int frame_count; +uniform float noise_scale; + +#define TEX_OFFSET(off) @{texture}(tex, texCoord - off / texSize) +#define WRAP(x, low, high) mod((x)-(low), (high)-(low)) + (low) + +float random(in vec3 value) { + float random = dot(sin(value), vec3(12.9898, 78.233, 37.719)); + return fract(sin(random) * 143758.5453); +} + +vec4 fromLinear(vec4 linearRGB){ + bvec3 cutoff = lessThan(linearRGB.rgb, vec3(0.0031308)); + vec3 higher = vec3(1.055)*pow(linearRGB.rgb, vec3(1.0/2.4)) - vec3(0.055); + vec3 lower = linearRGB.rgb * vec3(12.92); + return vec4(mix(higher, lower, cutoff), linearRGB.a); +} + +@if(o_current_filter == FILTER_THREE_POINT) +vec4 filter3point(in sampler2D tex, in vec2 texCoord, in vec2 texSize) { + vec2 offset = fract(texCoord*texSize - vec2(0.5)); + offset -= step(1.0, offset.x + offset.y); + vec4 c0 = TEX_OFFSET(offset); + vec4 c1 = TEX_OFFSET(vec2(offset.x - sign(offset.x), offset.y)); + vec4 c2 = TEX_OFFSET(vec2(offset.x, offset.y - sign(offset.y))); + return c0 + abs(offset.x)*(c1-c0) + abs(offset.y)*(c2-c0); +} + +vec4 hookTexture2D(in sampler2D tex, in vec2 uv, in vec2 texSize) { + return filter3point(tex, uv, texSize); +} +@else +vec4 hookTexture2D(in sampler2D tex, in vec2 uv, in vec2 texSize) { + return @{texture}(tex, uv); +} +@end + +void main() { + @for(i in 0..2) + @if(o_textures[i]) + @{s = o_clamp[i][0]} + @{t = o_clamp[i][1]} + + @if(opengles) + vec2 texSize@{i} = vec2(textureSize(uTex@{i}, 0)); + @else + vec2 texSize@{i} = textureSize(uTex@{i}, 0); + @end + + @if(!s && !t) + vec2 vTexCoordAdj@{i} = vTexCoord@{i}; + @else + @if(s && t) + vec2 vTexCoordAdj@{i} = clamp(vTexCoord@{i}, 0.5 / texSize@{i}, vec2(vTexClampS@{i}, vTexClampT@{i})); + @elseif(s) + vec2 vTexCoordAdj@{i} = vec2(clamp(vTexCoord@{i}.s, 0.5 / texSize@{i}.s, vTexClampS@{i}), vTexCoord@{i}.t); + @else + vec2 vTexCoordAdj@{i} = vec2(vTexCoord@{i}.s, clamp(vTexCoord@{i}.t, 0.5 / texSize@{i}.t, vTexClampT@{i})); + @end + @end + + vec4 texVal@{i} = hookTexture2D(uTex@{i}, vTexCoordAdj@{i}, texSize@{i}); + + @if(o_masks[i]) + @if(opengles) + vec2 maskSize@{i} = vec2(textureSize(uTexMask@{i}, 0)); + @else + vec2 maskSize@{i} = textureSize(uTexMask@{i}, 0); + @end + + vec4 maskVal@{i} = hookTexture2D(uTexMask@{i}, vTexCoordAdj@{i}, maskSize@{i}); + + @if(o_blend[i]) + vec4 blendVal@{i} = hookTexture2D(uTexBlend@{i}, vTexCoordAdj@{i}, texSize@{i}); + @else + vec4 blendVal@{i} = vec4(0, 0, 0, 0); + @end + + texVal@{i} = mix(texVal@{i}, blendVal@{i}, maskVal@{i}.a); + @end + @end + @end + + @if(o_alpha) + vec4 texel; + @else + vec3 texel; + @end + + @if(o_2cyc) + @{f_range = 2} + @else + @{f_range = 1} + @end + + @for(c in 0..f_range) + @if(c == 1) + @if(o_alpha) + @if(o_c[c][1][2] == SHADER_COMBINED) + texel.a = WRAP(texel.a, -1.01, 1.01); + @else + texel.a = WRAP(texel.a, -0.51, 1.51); + @end + @end + + @if(o_c[c][0][2] == SHADER_COMBINED) + texel.rgb = WRAP(texel.rgb, -1.01, 1.01); + @else + texel.rgb = WRAP(texel.rgb, -0.51, 1.51); + @end + @end + + @if(!o_color_alpha_same[c] && o_alpha) + texel = vec4(@{ + append_formula(o_c[c], o_do_single[c][0], + o_do_multiply[c][0], o_do_mix[c][0], false, false, true, c == 0) + }, @{append_formula(o_c[c], o_do_single[c][1], + o_do_multiply[c][1], o_do_mix[c][1], true, true, true, c == 0) + }); + @else + texel = @{append_formula(o_c[c], o_do_single[c][0], + o_do_multiply[c][0], o_do_mix[c][0], o_alpha, false, + o_alpha, c == 0)}; + @end + @end + + texel = WRAP(texel, -0.51, 1.51); + texel = clamp(texel, 0.0, 1.0); + // TODO discard if alpha is 0? + @if(o_fog) + @if(o_alpha) + texel = vec4(mix(texel.rgb, vFog.rgb, vFog.a), texel.a); + @else + texel = mix(texel, vFog.rgb, vFog.a); + @end + @end + + @if(o_texture_edge && o_alpha) + if (texel.a > 0.19) texel.a = 1.0; else discard; + @end + + @if(o_alpha && o_noise) + texel.a *= floor(clamp(random(vec3(floor(gl_FragCoord.xy * noise_scale), float(frame_count))) + texel.a, 0.0, 1.0)); + @end + + @if(o_grayscale) + float intensity = (texel.r + texel.g + texel.b) / 3.0; + vec3 new_texel = vGrayscaleColor.rgb * intensity; + texel.rgb = mix(texel.rgb, new_texel, vGrayscaleColor.a); + @end + + @if(o_alpha) + @if(o_alpha_threshold) + if (texel.a < 8.0 / 256.0) discard; + @end + @if(o_invisible) + texel.a = 0.0; + @end + @{vOutColor} = texel; + @else + @{vOutColor} = vec4(texel, 1.0); + @end + + @if(srgb_mode) + @{vOutColor} = fromLinear(@{vOutColor}); + @end +} \ No newline at end of file diff --git a/port/shaders/opengl/default.shader.vs b/port/shaders/opengl/default.shader.vs new file mode 100644 index 00000000..cf0f6276 --- /dev/null +++ b/port/shaders/opengl/default.shader.vs @@ -0,0 +1,79 @@ +@prism(type='fragment', name='Fast3D Fragment Shader', version='1.0.0', description='Ported shader to prism', author='Emill & Prism Team') + +@{GLSL_VERSION} + +@{attr} vec4 aVtxPos; + +@for(i in 0..2) + @if(o_textures[i]) + @{attr} vec2 aTexCoord@{i}; + @{out} vec2 vTexCoord@{i}; + @{update_floats(2)} + @for(j in 0..2) + @if(o_clamp[i][j]) + @if(j == 0) + @{attr} float aTexClampS@{i}; + @{out} float vTexClampS@{i}; + @else + @{attr} float aTexClampT@{i}; + @{out} float vTexClampT@{i}; + @end + @{update_floats(1)} + @end + @end + @end +@end + +@if(o_fog) + @{attr} vec4 aFog; + @{out} vec4 vFog; + @{update_floats(4)} +@end + +@if(o_grayscale) + @{attr} vec4 aGrayscaleColor; + @{out} vec4 vGrayscaleColor; + @{update_floats(4)} +@end + +@for(i in 0..o_inputs) + @if(o_alpha) + @{attr} vec4 aInput@{i + 1}; + @{out} vec4 vInput@{i + 1}; + @{update_floats(4)} + @else + @{attr} vec3 aInput@{i + 1}; + @{out} vec3 vInput@{i + 1}; + @{update_floats(3)} + @end +@end + +void main() { + @for(i in 0..2) + @if(o_textures[i]) + vTexCoord@{i} = aTexCoord@{i}; + @for(j in 0..2) + @if(o_clamp[i][j]) + @if(j == 0) + vTexClampS@{i} = aTexClampS@{i}; + @else + vTexClampT@{i} = aTexClampT@{i}; + @end + @end + @end + @end + @end + @if(o_fog) + vFog = aFog; + @end + @if(o_grayscale) + vGrayscaleColor = aGrayscaleColor; + @end + @for(i in 0..o_inputs) + vInput@{i + 1} = aInput@{i + 1}; + @end + gl_Position = aVtxPos; + @if(opengles) + gl_Position.z *= 0.3f; + @end +} \ No newline at end of file diff --git a/tools/Torch b/tools/Torch index 7598e293..228a17c6 160000 --- a/tools/Torch +++ b/tools/Torch @@ -1 +1 @@ -Subproject commit 7598e2932c3b8e0c08cddd2ac52ab735dbeefdf0 +Subproject commit 228a17c68282092b6c3937c46b943229388931fe