Merge commit '7621e2f8dec938cf48181c8b10afc9b01f444e68' into beta

This commit is contained in:
Ilya Laktyushin
2025-12-06 02:17:48 +04:00
commit 8344b97e03
28070 changed files with 7995182 additions and 0 deletions
@@ -0,0 +1,204 @@
#include <metal_stdlib>
#include "EditorCommon.h"
#include "EditorUtils.h"
using namespace metal;
typedef struct {
float2 dimensions;
float aspectRatio;
float shadows;
float highlights;
float contrast;
float fade;
float saturation;
float shadowsTintIntensity;
float3 shadowsTintColor;
float highlightsTintIntensity;
float3 highlightsTintColor;
float exposure;
float warmth;
float grain;
float vignette;
float hasCurves;
float2 empty;
} MediaEditorAdjustments;
half3 fade(half3 color, float fadeAmount) {
half3 comp1 = half3(-0.9772) * half3(pow(float3(color), float3(3.0)));
half3 comp2 = half3(1.708) * half3(pow(float3(color), float3(2.0)));
half3 comp3 = half3(-0.1603) * color;
half3 comp4 = half3(0.2878);
half3 finalComponent = comp1 + comp2 + comp3 + comp4;
half3 difference = finalComponent - color;
half3 scalingValue = half3(0.9);
half3 faded = color + (difference * scalingValue);
return (color * (1.0 - fadeAmount)) + (faded * fadeAmount);
}
float3 tintRaiseShadowsCurve(half3 color) {
float3 comp1 = float3(-0.003671) * pow(float3(color), float3(3.0));
float3 comp2 = float3(0.3842) * pow(float3(color), float3(2.0));
float3 comp3 = float3(0.3764) * float3(color);
float3 comp4 = float3(0.2515);
return comp1 + comp2 + comp3 + comp4;
}
half3 tintShadows(half3 color, float3 tintColor, float tintAmount) {
float3 raisedShadows = tintRaiseShadowsCurve(color);
float3 tintedShadows = mix(float3(color), raisedShadows, tintColor);
float3 tintedShadowsWithAmount = mix(float3(color), tintedShadows, tintAmount);
return half3(clamp(tintedShadowsWithAmount, 0.0, 1.0));
}
half3 tintHighlights(half3 color, float3 tintColor, float tintAmount) {
float3 loweredHighlights = float3(1.0) - tintRaiseShadowsCurve(half3(1.0) - color);
float3 tintedHighlights = mix(float3(color), loweredHighlights, (float3(1.0) - tintColor));
float3 tintedHighlightsWithAmount = mix(float3(color), tintedHighlights, tintAmount);
return half3(clamp(tintedHighlightsWithAmount, 0.0, 1.0));
}
half3 applyLuminanceCurve(half3 pixel, constant float allCurve[200]) {
int index = int(clamp(pixel.z / (1.0 / 200.0), 0.0, 199.0));
float value = allCurve[index];
float grayscale = (smoothstep(0.0, 0.1, float(pixel.z)) * (1.0 - smoothstep(0.8, 1.0, float(pixel.z))));
half saturation = mix(0.0, float(pixel.y), grayscale);
pixel.y = saturation;
pixel.z = value;
return pixel;
}
half3 applyRGBCurve(half3 pixel, constant float redCurve[200], constant float greenCurve[200], constant float blueCurve[200]) {
int index = int(clamp(pixel.r / (1.0 / 200.0), 0.0, 199.0));
float value = redCurve[index];
pixel.r = value;
index = int(clamp(pixel.g / (1.0 / 200.0), 0.0, 199.0));
value = greenCurve[index];
pixel.g = clamp(value, 0.0, 1.0);
index = int(clamp(pixel.b / (1.0 / 200.0), 0.0, 199.0));
value = blueCurve[index];
pixel.b = clamp(value, 0.0, 1.0);
return pixel;
}
fragment half4 adjustmentsFragmentShader(RasterizerData in [[stage_in]],
texture2d<half, access::sample> sourceImage [[texture(0)]],
constant MediaEditorAdjustments& adjustments [[buffer(0)]],
constant float allCurve [[buffer(1)]][200],
constant float redCurve [[buffer(2)]][200],
constant float greenCurve [[buffer(3)]][200],
constant float blueCurve [[buffer(4)]][200]
) {
constexpr sampler samplr(filter::linear, mag_filter::linear, min_filter::linear);
const float epsilon = 0.005;
half4 source = sourceImage.sample(samplr, float2(in.texCoord.x, in.texCoord.y));
half4 result = source;
if (adjustments.hasCurves > epsilon) {
result = half4(applyRGBCurve(hslToRgb(applyLuminanceCurve(rgbToHsl(result.rgb), allCurve)), redCurve, greenCurve, blueCurve), result.a);
}
if (abs(adjustments.highlights) > epsilon || abs(adjustments.shadows) > epsilon) {
const float3 hsLuminanceWeighting = float3(0.3, 0.3, 0.3);
float mappedHighlights = adjustments.highlights * 0.75 + 1.0;
float mappedShadows = adjustments.shadows * 0.55 + 1.0;
float hsLuminance = dot(float3(result.rgb), hsLuminanceWeighting);
float shadow = clamp((pow(hsLuminance, 1.0 / mappedShadows) - 0.76 * pow(hsLuminance, 2.0 / mappedShadows)) - hsLuminance, 0.0, 1.0);
float highlight = clamp((1.0 - (pow(1.0 - hsLuminance, 1.0 / (2.0 - mappedHighlights)) - 0.8 * pow(1.0 - hsLuminance, 2.0 / (2.0 - mappedHighlights)))) - hsLuminance, -1.0, 0.0);
float3 hsResult = float3(0.0, 0.0, 0.0) + ((hsLuminance + shadow + highlight) - 0.0) * ((float3(result.rgb) - float3(0.0, 0.0, 0.0)) / (hsLuminance - 0.0));
float contrastedLuminance = ((hsLuminance - 0.5) * 1.5) + 0.5;
float whiteInterp = contrastedLuminance * contrastedLuminance * contrastedLuminance;
half whiteTarget = clamp(mappedHighlights, 1.0, 2.0) - 1.0;
hsResult = mix(hsResult, float3(1.0), whiteInterp * whiteTarget);
float invContrastedLuminance = 1.0 - contrastedLuminance;
float blackInterp = invContrastedLuminance * invContrastedLuminance * invContrastedLuminance;
half blackTarget = 1.0 - clamp(mappedShadows, 0.0, 1.0);
result.rgb = half3(mix(hsResult, float3(0.0), blackInterp * blackTarget));
}
if (abs(adjustments.contrast) > epsilon) {
half mappedContrast = half(adjustments.contrast) * 0.3 + 1.0;
result.rgb = clamp(((result.rgb - half3(0.5)) * mappedContrast + half3(0.5)), 0.0, 1.0);
}
if (abs(adjustments.fade) > epsilon) {
result.rgb = fade(result.rgb, adjustments.fade);
}
if (abs(adjustments.saturation) > epsilon) {
float mappedSaturation = adjustments.saturation;
if (mappedSaturation > 0.0) {
mappedSaturation *= 1.05;
}
mappedSaturation += 1.0;
half satLuminance = dot(result.rgb, half3(0.2126, 0.7152, 0.0722));
half3 greyScaleColor = half3(satLuminance);
result.rgb = clamp(mix(greyScaleColor, result.rgb, mappedSaturation), 0.0, 1.0);
}
if (abs(adjustments.shadowsTintIntensity) > epsilon) {
result.rgb = tintShadows(result.rgb, adjustments.shadowsTintColor, adjustments.shadowsTintIntensity * 2.0);
}
if (abs(adjustments.highlightsTintIntensity) > epsilon) {
result.rgb = tintHighlights(result.rgb, adjustments.highlightsTintColor, adjustments.highlightsTintIntensity * 2.0);
}
if (abs(adjustments.exposure) > epsilon) {
float mag = adjustments.exposure * 1.045;
float power = 1.0 + abs(mag);
if (mag < 0.0) {
power = 1.0 / power;
}
result.r = 1.0 - pow((1.0 - result.r), power);
result.g = 1.0 - pow((1.0 - result.g), power);
result.b = 1.0 - pow((1.0 - result.b), power);
}
if (abs(adjustments.warmth) > epsilon) {
half3 yuvVector;
if (adjustments.warmth > 0.0) {
yuvVector = half3(0.1765, -0.1255, 0.0902);
} else {
yuvVector = -half3(0.0588, 0.1569, -0.1255);
}
half3 yuvColor = rgbToYuv(result.rgb);
half luma = yuvColor.r;
half curveScale = sin(luma * 3.14159);
yuvColor += 0.375 * adjustments.warmth * curveScale * yuvVector;
result.rgb = yuvToRgb(yuvColor);
}
if (abs(adjustments.vignette) > epsilon) {
const float midpoint = 0.7;
const float fuzziness = 0.62;
float radDist = length(in.texCoord - 0.5) / sqrt(0.5);
float mag = easeInOutSigmoid(radDist * midpoint, fuzziness) * adjustments.vignette * 0.645;
result.rgb = half3(mix(pow(float3(result.rgb), float3(1.0 / (1.0 - mag))), float3(0.0), mag * mag));
}
if (abs(adjustments.grain) > epsilon) {
const float grainSize = 2.3;
float3 rotOffset = float3(1.425, 3.892, 5.835);
float2 rotCoordsR = coordRot(in.texCoord, rotOffset.x);
half3 noise = half3(pnoise3D(float3(rotCoordsR * float2(adjustments.dimensions.x / grainSize, adjustments.dimensions.y / grainSize), 0.0)));
half3 lumcoeff = half3(0.299, 0.587, 0.114);
float luminance = dot(result.rgb, lumcoeff);
float lum = smoothstep(0.2, 0.0, luminance);
lum += luminance;
noise = mix(noise, half3(0.0), pow(lum, 4.0));
result.rgb = result.rgb + noise * adjustments.grain * 0.04;
}
return half4(result.rgb * result.a, result.a);
}
@@ -0,0 +1,72 @@
#include <metal_stdlib>
#include "EditorCommon.h"
#include "EditorUtils.h"
using namespace metal;
typedef struct {
float2 dimensions;
float2 position;
float aspectRatio;
float size;
float falloff;
float rotation;
} MediaEditorBlur;
fragment half4 blurRadialFragmentShader(RasterizerData in [[stage_in]],
texture2d<half, access::sample> sourceTexture [[texture(0)]],
texture2d<half, access::sample> blurTexture [[texture(1)]],
constant MediaEditorBlur& values [[ buffer(0) ]]
)
{
constexpr sampler sourceSampler(min_filter::linear, mag_filter::linear, address::clamp_to_zero);
constexpr sampler blurSampler(min_filter::linear, mag_filter::linear, address::clamp_to_zero);
half4 sourceColor = sourceTexture.sample(sourceSampler, in.texCoord);
half4 blurredColor = blurTexture.sample(blurSampler, in.texCoord);
float2 texCoord = float2(in.texCoord.x, (in.texCoord.y * values.aspectRatio + 0.5 - 0.5 * values.aspectRatio));
half distanceFromCenter = distance(values.position, texCoord);
half3 result = mix(blurredColor.rgb, sourceColor.rgb, smoothstep(1.0, values.falloff, clamp(distanceFromCenter / values.size, 0.0, 1.0)));
return half4(result, sourceColor.a);
}
fragment half4 blurLinearFragmentShader(RasterizerData in [[stage_in]],
texture2d<half, access::sample> sourceTexture [[texture(0)]],
texture2d<half, access::sample> blurTexture [[texture(1)]],
constant MediaEditorBlur& values [[ buffer(0) ]]
)
{
constexpr sampler sourceSampler(min_filter::linear, mag_filter::linear, address::clamp_to_zero);
constexpr sampler blurSampler(min_filter::linear, mag_filter::linear, address::clamp_to_zero);
half4 sourceColor = sourceTexture.sample(sourceSampler, in.texCoord);
half4 blurredColor = blurTexture.sample(blurSampler, in.texCoord);
float2 texCoord = float2(in.texCoord.x, (in.texCoord.y * values.aspectRatio + 0.5 - 0.5 * values.aspectRatio));
half distanceFromCenter = abs((texCoord.x - values.position.x) * sin(-values.rotation) + (texCoord.y - values.position.y) * cos(-values.rotation));
half3 result = mix(blurredColor.rgb, sourceColor.rgb, smoothstep(1.0, values.falloff, clamp(distanceFromCenter / values.size, 0.0, 1.0)));
return half4(result, sourceColor.a);
}
fragment half4 blurPortraitFragmentShader(RasterizerData in [[stage_in]],
texture2d<half, access::sample> sourceTexture [[texture(0)]],
texture2d<half, access::sample> blurTexture [[texture(1)]],
texture2d<half, access::sample> maskTexture [[texture(2)]],
constant MediaEditorBlur& values [[ buffer(0) ]]
)
{
constexpr sampler sourceSampler(min_filter::linear, mag_filter::linear, address::clamp_to_zero);
constexpr sampler blurSampler(min_filter::linear, mag_filter::linear, address::clamp_to_zero);
constexpr sampler maskSampler(min_filter::linear, mag_filter::linear, address::clamp_to_zero);
half4 sourceColor = sourceTexture.sample(sourceSampler, in.texCoord);
half4 blurredColor = blurTexture.sample(blurSampler, in.texCoord);
half4 maskColor = maskTexture.sample(maskSampler, in.texCoord);
half3 result = mix(blurredColor.rgb, sourceColor.rgb, maskColor.r);
return half4(result, sourceColor.a);
}
@@ -0,0 +1,9 @@
#include <metal_stdlib>
#pragma once
typedef struct {
float4 pos [[position]];
float2 texCoord;
float2 localPos;
} RasterizerData;
@@ -0,0 +1,50 @@
#include <metal_stdlib>
#include "EditorCommon.h"
using namespace metal;
typedef struct {
float4 pos;
float2 texCoord;
float2 localPos;
} VertexData;
vertex RasterizerData defaultVertexShader(uint vertexID [[vertex_id]],
constant VertexData *vertices [[buffer(0)]]) {
RasterizerData out;
out.pos = vector_float4(0.0, 0.0, 0.0, 1.0);
out.pos.xy = vertices[vertexID].pos.xy;
out.localPos = vertices[vertexID].localPos.xy;
out.texCoord = vertices[vertexID].texCoord;
return out;
}
fragment half4 defaultFragmentShader(RasterizerData in [[stage_in]],
texture2d<half, access::sample> texture [[texture(0)]]) {
constexpr sampler samplr(filter::linear, mag_filter::linear, min_filter::linear);
half4 color = texture.sample(samplr, in.texCoord);
return color;
}
fragment half histogramPrepareFragmentShader(RasterizerData in [[stage_in]],
texture2d<half, access::sample> texture [[texture(0)]]) {
constexpr sampler samplr(filter::linear, mag_filter::linear, min_filter::linear);
half3 color = texture.sample(samplr, in.texCoord).rgb;
half luma = color.r * 0.3 + color.g * 0.59 + color.b * 0.11;
return luma;
}
typedef struct {
float4 topColor;
float4 bottomColor;
} GradientColors;
fragment half4 gradientFragmentShader(RasterizerData in [[stage_in]],
constant GradientColors& colors [[buffer(0)]]) {
return half4(half3(mix(colors.topColor.rgb, colors.bottomColor.rgb, in.texCoord.y)), 1.0);
}
@@ -0,0 +1,46 @@
#include <metal_stdlib>
#include "EditorCommon.h"
#include "EditorUtils.h"
using namespace metal;
typedef struct {
float2 dimensions;
float roundness;
float alpha;
float isOpaque;
float empty;
} VideoEncodeParameters;
typedef struct {
float4 pos;
float2 texCoord;
float4 localPos;
} VertexData;
fragment half4 dualFragmentShader(RasterizerData in [[stage_in]],
texture2d<half, access::sample> texture [[texture(0)]],
texture2d<half, access::sample> mask [[texture(1)]],
constant VideoEncodeParameters& adjustments [[buffer(0)]]
) {
float2 R = float2(adjustments.dimensions.x, adjustments.dimensions.y);
float2 uv = (in.localPos - float2(0.5, 0.5)) * 2.0;
if (R.x > R.y) {
uv.y = uv.y * R.y / R.x;
} else {
uv.x = uv.x * R.x / R.y;
}
float aspectRatio = R.x / R.y;
constexpr sampler samplr(filter::linear, mag_filter::linear, min_filter::linear);
half4 color = texture.sample(samplr, in.texCoord);
float colorAlpha = min(1.0, adjustments.isOpaque * color.a + mask.sample(samplr, in.texCoord).r);
float t = 1.0 / adjustments.dimensions.y;
float side = 1.0 * aspectRatio;
float distance = smoothstep(t, -t, sdfRoundedRectangle(uv, float2(0.0, 0.0), float2(side, mix(1.0, side, adjustments.roundness)), side * adjustments.roundness));
return mix(half4(color.rgb, 0.0), half4(color.rgb, colorAlpha * adjustments.alpha), distance);
}
@@ -0,0 +1,119 @@
#include <metal_stdlib>
#include "EditorCommon.h"
#include "EditorUtils.h"
using namespace metal;
typedef struct {
uint histogramBins;
uint clipLimit;
uint totalPixelCountPerTile;
uint numberOfLUTs;
} MediaEditorEnhanceLUTGeneratorParameters;
fragment half rgbToLightnessFragmentShader(RasterizerData in [[ stage_in ]],
texture2d<half, access::sample> sourceTexture [[ texture(0) ]],
sampler colorSampler [[ sampler(0) ]],
constant float2 & scale [[buffer(0)]])
{
half4 color = sourceTexture.sample(colorSampler, in.texCoord * scale);
half3 hsl = rgbToHsl(color.rgb);
return hsl.b;
}
kernel void enhanceGenerateLUT(texture2d<float, access::write> outTexture [[texture(0)]],
device uint * histogramBuffer [[buffer(0)]],
constant MediaEditorEnhanceLUTGeneratorParameters & parameters [[buffer(1)]],
uint gid [[thread_position_in_grid]])
{
if (gid >= parameters.numberOfLUTs) {
return;
}
device uint *l = histogramBuffer + gid * parameters.histogramBins;
const uint histSize = parameters.histogramBins;
uint clipped = 0;
for (uint i = 0; i < histSize; ++i) {
if(l[i] > parameters.clipLimit) {
clipped += (l[i] - parameters.clipLimit);
l[i] = parameters.clipLimit;
}
}
const uint redistBatch = clipped / histSize;
uint residual = clipped - redistBatch * histSize;
for (uint i = 0; i < histSize; ++i) {
l[i] += redistBatch;
}
if (residual != 0) {
const uint residualStep = max(histSize / residual, (uint)1);
for (uint i = 0; i < histSize && residual > 0; i += residualStep, residual--) {
l[i]++;
}
}
uint sum = 0;
const float lutScale = (histSize - 1) / float(parameters.totalPixelCountPerTile);
for (uint index = 0; index < histSize; ++index) {
sum += l[index];
outTexture.write(round(sum * lutScale) / 255.0, uint2(index, gid));
}
}
half enhanceLookup(texture2d<half, access::sample> lutTexture, sampler lutSamper, float index, float x) {
return lutTexture.sample(lutSamper, float2(x, (index + 0.5)/lutTexture.get_height())).r;
}
fragment half4 enhanceColorLookupFragmentShader(RasterizerData in [[stage_in]],
texture2d<half, access::sample> sourceTexture [[texture(0)]],
texture2d<half, access::sample> lutTexture [[texture(1)]],
constant float2 & tileGridSize [[ buffer(0) ]],
constant float & intensity [[ buffer(1) ]]
)
{
constexpr sampler colorSampler(min_filter::linear, mag_filter::linear, address::clamp_to_zero);
constexpr sampler lutSampler(min_filter::linear, mag_filter::linear, address::clamp_to_zero);
float2 sourceCoord = in.texCoord;
half4 color = sourceTexture.sample(colorSampler, sourceCoord);
half3 hslColor = rgbToHsl(color.rgb);
float txf = sourceCoord.x * tileGridSize.x - 0.5;
float tx1 = floor(txf);
float tx2 = tx1 + 1.0;
float xa_p = txf - tx1;
float xa1_p = 1.0 - xa_p;
tx1 = max(tx1, 0.0);
tx2 = min(tx2, tileGridSize.x - 1.0);
float tyf = sourceCoord.y * tileGridSize.y - 0.5;
float ty1 = floor(tyf);
float ty2 = ty1 + 1.0;
float ya = tyf - ty1;
float ya1 = 1.0 - ya;
ty1 = max(ty1, 0.0);
ty2 = min(ty2, tileGridSize.y - 1.0);
float srcVal = hslColor.b;
float x = (srcVal * 255.0 + 0.5) / lutTexture.get_width();
half lutPlane1_ind1 = enhanceLookup(lutTexture, lutSampler, ty1 * tileGridSize.x + tx1, x);
half lutPlane1_ind2 = enhanceLookup(lutTexture, lutSampler, ty1 * tileGridSize.x + tx2, x);
half lutPlane2_ind1 = enhanceLookup(lutTexture, lutSampler, ty2 * tileGridSize.x + tx1, x);
half lutPlane2_ind2 = enhanceLookup(lutTexture, lutSampler, ty2 * tileGridSize.x + tx2, x);
half res = (lutPlane1_ind1 * xa1_p + lutPlane1_ind2 * xa_p) * ya1 + (lutPlane2_ind1 * xa1_p + lutPlane2_ind2 * xa_p) * ya;
half3 r = half3(hslColor.r, min(1.0, hslColor.g * 1.25), min(1.0, res * 1.1));
half3 rgbResult = hslToRgb(r);
return half4(mix(color.rgb, rgbResult, half(intensity)), color.a);
}
@@ -0,0 +1,28 @@
#include <metal_stdlib>
#pragma once
half getLuma(half3 color);
half3 rgbToHsv(half3 c);
half3 hsvToRgb(half3 c);
half3 rgbToHsl(half3 color);
half hueToRgb(half f1, half f2, half hue);
half3 hslToRgb(half3 hsl);
half3 rgbToYuv(half3 inP);
half3 yuvToRgb(half3 inP);
half easeInOutSigmoid(half value, half strength);
half powerCurve(half inVal, half mag);
float pnoise3D(float3 p);
float2 coordRot(float2 tc, float angle);
float sdfRoundedRectangle(float2 uv, float2 position, float2 size, float radius);
@@ -0,0 +1,209 @@
#include <metal_stdlib>
#include "EditorUtils.h"
using namespace metal;
half getLuma(half3 color) {
return (0.299 * color.r) + (0.587 * color.g) + (0.114 * color.b);
}
half3 rgbToHsv(half3 c) {
half4 K = half4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
half4 p = c.g < c.b ? half4(c.bg, K.wz) : half4(c.gb, K.xy);
half4 q = c.r < p.x ? half4(p.xyw, c.r) : half4(c.r, p.yzx);
half d = q.x - min(q.w, q.y);
half e = 1.0e-10;
return half3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
half3 hsvToRgb(half3 c) {
half4 K = half4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
half3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
half3 rgbToHsl(half3 color) {
half3 hsl;
half fMin = min(min(color.r, color.g), color.b);
half fMax = max(max(color.r, color.g), color.b);
half delta = fMax - fMin;
hsl.z = (fMax + fMin) / 2.0;
if (delta == 0.0) {
hsl.x = 0.0;
hsl.y = 0.0;
} else {
if (hsl.z < 0.5) {
hsl.y = delta / (fMax + fMin);
} else {
hsl.y = delta / (2.0 - fMax - fMin);
}
half deltaR = (((fMax - color.r) / 6.0) + (delta / 2.0)) / delta;
half deltaG = (((fMax - color.g) / 6.0) + (delta / 2.0)) / delta;
half deltaB = (((fMax - color.b) / 6.0) + (delta / 2.0)) / delta;
if (color.r == fMax) {
hsl.x = deltaB - deltaG;
} else if (color.g == fMax) {
hsl.x = (1.0 / 3.0) + deltaR - deltaB;
} else if (color.b == fMax) {
hsl.x = (2.0 / 3.0) + deltaG - deltaR;
}
if (hsl.x < 0.0) {
hsl.x += 1.0;
} else if (hsl.x > 1.0) {
hsl.x -= 1.0;
}
}
return hsl;
}
half hueToRgb(half f1, half f2, half hue) {
if (hue < 0.0) {
hue += 1.0;
} else if (hue > 1.0) {
hue -= 1.0;
}
half res;
if ((6.0 * hue) < 1.0) {
res = f1 + (f2 - f1) * 6.0 * hue;
} else if ((2.0 * hue) < 1.0) {
res = f2;
} else if ((3.0 * hue) < 2.0) {
res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0;
} else {
res = f1;
}
return res;
}
half3 hslToRgb(half3 hsl) {
half3 rgb;
if (hsl.y == 0.0) {
rgb = half3(hsl.z);
} else {
half f2;
if (hsl.z < 0.5) {
f2 = hsl.z * (1.0 + hsl.y);
} else {
f2 = (hsl.z + hsl.y) - (hsl.y * hsl.z);
}
half f1 = 2.0 * hsl.z - f2;
rgb.r = hueToRgb(f1, f2, hsl.x + (1.0 / 3.0));
rgb.g = hueToRgb(f1, f2, hsl.x);
rgb.b = hueToRgb(f1, f2, hsl.x - (1.0 / 3.0));
}
return rgb;
}
half3 rgbToYuv(half3 inP) {
half3 outP;
outP.r = getLuma(inP);
outP.g = (1.0 / 1.772) * (inP.b - outP.r);
outP.b = (1.0 / 1.402) * (inP.r - outP.r);
return outP;
}
half3 yuvToRgb(half3 inP) {
float y = inP.r;
float u = inP.g;
float v = inP.b;
half3 outP;
outP.r = 1.402 * v + y;
outP.g = (y - (0.299 * 1.402 / 0.587) * v - (0.114 * 1.772 / 0.587) * u);
outP.b = 1.772 * u + y;
return outP;
}
half easeInOutSigmoid(half value, half strength) {
float t = 1.0 / (1.0 - strength);
if (value > 0.5) {
return 1.0 - pow(2.0 - 2.0 * value, t) * 0.5;
} else {
return pow(2.0 * value, t) * 0.5;
}
}
half powerCurve(half inVal, half mag) {
half outVal;
float power = 1.0 + abs(mag);
if (mag > 0.0) {
power = 1.0 / power;
}
inVal = 1.0 - inVal;
outVal = pow((1.0 - inVal), power);
return outVal;
}
float4 rnm(float2 tc) {
float noise = sin(dot(tc, float2(12.9898, 78.233))) * 43758.5453;
float noiseR = fract(noise) * 2.0-1.0;
float noiseG = fract(noise * 1.2154) * 2.0-1.0;
float noiseB = fract(noise * 1.3453) * 2.0-1.0;
float noiseA = fract(noise * 1.3647) * 2.0-1.0;
return float4(noiseR,noiseG,noiseB,noiseA);
}
float fade(float t) {
return t*t*t*(t*(t*6.0-15.0)+10.0);
}
float pnoise3D(float3 p) {
const half permTexUnit = 1.0 / 256.0;
const half permTexUnitHalf = 0.5 / 256.0;
float3 pi = permTexUnit * floor(p) + permTexUnitHalf;
float3 pf = fract(p);
// Noise contributions from (x=0, y=0), z=0 and z=1
float perm00 = rnm(pi.xy).a ;
float3 grad000 = rnm(float2(perm00, pi.z)).rgb * 4.0 - 1.0;
float n000 = dot(grad000, pf);
float3 grad001 = rnm(float2(perm00, pi.z + permTexUnit)).rgb * 4.0 - 1.0;
float n001 = dot(grad001, pf - float3(0.0, 0.0, 1.0));
// Noise contributions from (x=0, y=1), z=0 and z=1
float perm01 = rnm(pi.xy + float2(0.0, permTexUnit)).a ;
float3 grad010 = rnm(float2(perm01, pi.z)).rgb * 4.0 - 1.0;
float n010 = dot(grad010, pf - float3(0.0, 1.0, 0.0));
float3 grad011 = rnm(float2(perm01, pi.z + permTexUnit)).rgb * 4.0 - 1.0;
float n011 = dot(grad011, pf - float3(0.0, 1.0, 1.0));
// Noise contributions from (x=1, y=0), z=0 and z=1
float perm10 = rnm(pi.xy + float2(permTexUnit, 0.0)).a ;
float3 grad100 = rnm(float2(perm10, pi.z)).rgb * 4.0 - 1.0;
float n100 = dot(grad100, pf - float3(1.0, 0.0, 0.0));
float3 grad101 = rnm(float2(perm10, pi.z + permTexUnit)).rgb * 4.0 - 1.0;
float n101 = dot(grad101, pf - float3(1.0, 0.0, 1.0));
// Noise contributions from (x=1, y=1), z=0 and z=1
float perm11 = rnm(pi.xy + float2(permTexUnit, permTexUnit)).a ;
float3 grad110 = rnm(float2(perm11, pi.z)).rgb * 4.0 - 1.0;
float n110 = dot(grad110, pf - float3(1.0, 1.0, 0.0));
float3 grad111 = rnm(float2(perm11, pi.z + permTexUnit)).rgb * 4.0 - 1.0;
float n111 = dot(grad111, pf - float3(1.0, 1.0, 1.0));
// Blend contributions along x
float4 n_x = mix(float4(n000, n001, n010, n011), float4(n100, n101, n110, n111), fade(pf.x));
// Blend contributions along y
float2 n_xy = mix(n_x.xy, n_x.zw, fade(pf.y));
// Blend contributions along z
float n_xyz = mix(n_xy.x, n_xy.y, fade(pf.z));
return n_xyz;
}
float2 coordRot(float2 tc, float angle) {
float rotX = ((tc.x * 2.0 - 1.0) * cos(angle)) - ((tc.y * 2.0 - 1.0) * sin(angle));
float rotY = ((tc.y * 2.0 - 1.0) * cos(angle)) + ((tc.x * 2.0 - 1.0) * sin(angle));
rotX = rotX * 0.5 + 0.5;
rotY = rotY * 0.5 + 0.5;
return float2(rotX, rotY);
}
float sdfRoundedRectangle(float2 uv, float2 position, float2 size, float radius) {
float2 q = abs(uv - position) - size + radius;
return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - radius;
}
@@ -0,0 +1,62 @@
#include <metal_stdlib>
#include "EditorCommon.h"
#include "EditorUtils.h"
using namespace metal;
//static inline float sRGBnonLinearNormToLinear(float normV) {
// if (normV <= 0.04045f) {
// normV *= (1.0f / 12.92f);
// } else {
// const float a = 0.055f;
// const float gamma = 2.4f;
// normV = (normV + a) * (1.0f / (1.0f + a));
// normV = pow(normV, gamma);
// }
// return normV;
//}
//static inline float4 sRGBGammaDecode(const float4 rgba) {
// float4 result = rgba;
// result.r = sRGBnonLinearNormToLinear(rgba.r);
// result.g = sRGBnonLinearNormToLinear(rgba.g);
// result.b = sRGBnonLinearNormToLinear(rgba.b);
// return result;
//}
static inline float4 BT709Decode(const float Y, const float Cb, const float Cr) {
float Yn = Y;
float Cbn = (Cb - (128.0f/255.0f));
float Crn = (Cr - (128.0f/255.0f));
float3 YCbCr = float3(Yn, Cbn, Crn);
const float3x3 kColorConversion709 = float3x3(float3(1.0, 1.0, 1.0),
float3(0.0f, -0.18732, 1.8556),
float3(1.5748, -0.46812, 0.0));
float3 rgb = kColorConversion709 * YCbCr;
rgb = saturate(rgb);
return float4(rgb.r, rgb.g, rgb.b, 1.0f);
}
fragment float4 bt709ToRGBFragmentShader(RasterizerData in [[stage_in]],
texture2d<half, access::sample> inYTexture [[texture(0)]],
texture2d<half, access::sample> inUVTexture [[texture(1)]]
)
{
constexpr sampler textureSampler (mag_filter::nearest, min_filter::nearest);
float Y = float(inYTexture.sample(textureSampler, in.texCoord).r);
half2 uvSamples = inUVTexture.sample(textureSampler, in.texCoord).rg;
float Cb = float(uvSamples[0]);
float Cr = float(uvSamples[1]);
float4 pixel = BT709Decode(Y, Cb, Cr);
//pixel = sRGBGammaDecode(pixel);
return pixel;
}