27a9dfb65f
Rename LIGHT GLOW to HDF EFFECT and gate it behind PRO: LITE renders the chip greyed out with a PRO tag and cannot open its slider; restoration of older settings that carry hdf > 0 still blocks export in LITE. Play/licence pass: - drop unused permissions (ACTIVITY_RECOGNITION, READ_MEDIA_AUDIO/VIDEO, SYSTEM_ALERT_WINDOW) and requestLegacyExternalStorage - rename the Leica sims to LC STREETLIFE CLASSIC/VIVID, drop the brand from comments; fix app name text, canvaskit copyright, LICENSE owner - remove expo-image-picker and expo-sensors (no JS import), delete dead exports (computeMatrixTint, cinemaSeasonName, base64 helpers, formatCoordinate) - versionCode 3 / versionName 1.2.1, drop the personal email from About - add docs/privacy-policy.html for the Play listing Size: R8 + shrinkResources + bundle compression + ABI trim, 161 MB -> 76 MB.
139 lines
4.5 KiB
TypeScript
139 lines
4.5 KiB
TypeScript
import { CinemaSeason } from '../types';
|
|
|
|
// Cinematic seasonal atmosphere grade. Deliberately NOT a fake re-light: a
|
|
// still photo has no depth, so "moving the sun" would look plastic. Instead
|
|
// this reads the photo's EXISTING exposure and pushes it a certain way:
|
|
// - lit areas get the season's warm/golden tint + a soft sun glow (halation)
|
|
// - shadow side gets a complementary cool tint
|
|
// - a seasonal haze/fog veil blends toward a fog color (strongest in winter)
|
|
// That reads as "sunlight / morning mist" without inventing new light.
|
|
//
|
|
// Uniforms are 16 flat floats (scalar form keeps the JSX <Shader> uniforms
|
|
// object and the worklet/export flat arrays in the exact same order):
|
|
// strength, contrast, saturation, haze,
|
|
// warmR, warmG, warmB, warmAmt,
|
|
// coolR, coolG, coolB, coolAmt,
|
|
// fogR, fogG, fogB, fogAmt
|
|
export const CINEMA_SKSL = `
|
|
uniform shader src;
|
|
uniform float strength;
|
|
uniform float contrast;
|
|
uniform float saturation;
|
|
uniform float haze;
|
|
uniform float warmR;
|
|
uniform float warmG;
|
|
uniform float warmB;
|
|
uniform float warmAmt;
|
|
uniform float coolR;
|
|
uniform float coolG;
|
|
uniform float coolB;
|
|
uniform float coolAmt;
|
|
uniform float fogR;
|
|
uniform float fogG;
|
|
uniform float fogB;
|
|
uniform float fogAmt;
|
|
vec4 main(vec2 xy) {
|
|
vec4 c = src.eval(xy);
|
|
float t = clamp(dot(c.rgb, vec3(0.2126, 0.7152, 0.0722)), 0.0, 1.0);
|
|
vec3 r = c.rgb;
|
|
// Filmic-ish gentle contrast on the luma (keeps hue).
|
|
r = mix(r, clamp((r - 0.5) * (1.0 + contrast * strength) + 0.5, 0.0, 1.0), strength);
|
|
// Saturation.
|
|
float l = dot(r, vec3(0.2126, 0.7152, 0.0722));
|
|
r = mix(vec3(l), r, mix(1.0, saturation, strength));
|
|
// Season tints follow the EXISTING light: warm on lit areas, cool in shade.
|
|
float lit = smoothstep(0.30, 1.0, t);
|
|
float shad = 1.0 - smoothstep(0.0, 0.45, t);
|
|
vec3 warm = vec3(warmR, warmG, warmB);
|
|
vec3 cool = vec3(coolR, coolG, coolB);
|
|
r *= 1.0 + (warm - 1.0) * lit * warmAmt * strength;
|
|
r *= 1.0 + (cool - 1.0) * shad * coolAmt * strength;
|
|
// Soft sun glow at the brightest points (halation of existing highlights).
|
|
float glow = smoothstep(0.65, 1.0, t);
|
|
r += warm * glow * warmAmt * 0.45 * strength;
|
|
// Atmospheric haze/fog veil (lightest shadow side => misty air).
|
|
vec3 fog = vec3(fogR, fogG, fogB);
|
|
r = mix(r, fog, fogAmt * strength * (0.3 + 0.7 * shad));
|
|
return vec4(clamp(r, 0.0, 1.0), c.a);
|
|
}
|
|
`;
|
|
|
|
export interface CinemaUniformSet {
|
|
season: CinemaSeason;
|
|
// 16 flat floats — order matches CINEMA_SKSL declaration order above.
|
|
flat: number[];
|
|
// Name-keyed, for the JSX <Shader uniforms={...}> form.
|
|
uniforms: Record<string, number>;
|
|
}
|
|
|
|
const ZERO: Record<string, number> = {};
|
|
|
|
const SEASONS: Record<CinemaSeason, { name: string; values: number[] }> = {
|
|
// Soft fresh light, gentle warm haze, barely-there cool in shade.
|
|
spring: {
|
|
name: 'CINEMA SPRING',
|
|
values: [
|
|
0.6, 0.08, 1.04, 0.18,
|
|
1.02, 0.998, 0.95, 0.3,
|
|
0.97, 0.995, 1.03, 0.12,
|
|
0.95, 0.96, 0.98, 0.16,
|
|
],
|
|
},
|
|
// Golden hour-ish high sun: strong warm on lit, bluish shade, crisp.
|
|
summer: {
|
|
name: 'CINEMA SUMMER',
|
|
values: [
|
|
0.75, 0.2, 1.12, 0.1,
|
|
1.08, 1.04, 0.88, 0.4,
|
|
0.93, 0.97, 1.06, 0.2,
|
|
1.0, 0.97, 0.88, 0.05,
|
|
],
|
|
},
|
|
// Amber low sun + warm atmospheric haze.
|
|
autumn: {
|
|
name: 'CINEMA AUTUMN',
|
|
values: [
|
|
0.8, 0.16, 1.1, 0.24,
|
|
1.12, 1.02, 0.78, 0.42,
|
|
1.02, 0.98, 0.88, 0.16,
|
|
1.0, 0.93, 0.75, 0.18,
|
|
],
|
|
},
|
|
// Cold winter fog: desaturated, blue-grey, heavy mist, no warm sun.
|
|
winter: {
|
|
name: 'CINEMA WINTER',
|
|
values: [
|
|
0.65, -0.02, 0.88, 0.38,
|
|
0.99, 0.995, 1.02, 0.06,
|
|
0.94, 0.97, 1.08, 0.3,
|
|
0.9, 0.93, 0.97, 0.45,
|
|
],
|
|
},
|
|
};
|
|
|
|
const KEYS = [
|
|
'strength', 'contrast', 'saturation', 'haze',
|
|
'warmR', 'warmG', 'warmB', 'warmAmt',
|
|
'coolR', 'coolG', 'coolB', 'coolAmt',
|
|
'fogR', 'fogG', 'fogB', 'fogAmt',
|
|
] as const;
|
|
|
|
export function getCinemaUniforms(season: CinemaSeason | null | undefined): CinemaUniformSet | null {
|
|
if (!season) return null;
|
|
const s = SEASONS[season];
|
|
if (!s) return null;
|
|
const uniforms: Record<string, number> = {};
|
|
KEYS.forEach((k, i) => (uniforms[k] = s.values[i]));
|
|
return { season, flat: s.values, uniforms };
|
|
}
|
|
|
|
// Zeroed 16-float block — used to turn the cinema pass OFF in the worklet
|
|
// synchronizable (strength === 0 means inactive there).
|
|
export function cinemaOffFlat(): number[] {
|
|
return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
|
}
|
|
|
|
export function cinemaIsActive(flat: number[] | null | undefined): boolean {
|
|
return !!flat && flat.length === 16 && flat[0] > 0;
|
|
}
|