refactor: シェーダーファイルをlazy-loadingできるように
This commit is contained in:
parent
df315b18e0
commit
a1ab2fa38c
|
@ -166,7 +166,7 @@ onMounted(async () => {
|
||||||
|
|
||||||
await renderer.setLayers(layers);
|
await renderer.setLayers(layers);
|
||||||
|
|
||||||
renderer.render();
|
await renderer.render();
|
||||||
|
|
||||||
closeWaiting();
|
closeWaiting();
|
||||||
});
|
});
|
||||||
|
@ -193,7 +193,7 @@ async function save() {
|
||||||
await nextTick(); // waitingがレンダリングされるまで待つ
|
await nextTick(); // waitingがレンダリングされるまで待つ
|
||||||
|
|
||||||
renderer.changeResolution(imageBitmap.width, imageBitmap.height); // 本番レンダリングのためオリジナル画質に戻す
|
renderer.changeResolution(imageBitmap.width, imageBitmap.height); // 本番レンダリングのためオリジナル画質に戻す
|
||||||
renderer.render(); // toBlobの直前にレンダリングしないと何故か壊れる
|
await renderer.render(); // toBlobの直前にレンダリングしないと何故か壊れる
|
||||||
canvasEl.value.toBlob((blob) => {
|
canvasEl.value.toBlob((blob) => {
|
||||||
emit('ok', new File([blob!], `image-${Date.now()}.png`, { type: 'image/png' }));
|
emit('ok', new File([blob!], `image-${Date.now()}.png`, { type: 'image/png' }));
|
||||||
dialog.value?.close();
|
dialog.value?.close();
|
||||||
|
@ -202,14 +202,14 @@ async function save() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const enabled = ref(true);
|
const enabled = ref(true);
|
||||||
watch(enabled, () => {
|
watch(enabled, async () => {
|
||||||
if (renderer != null) {
|
if (renderer != null) {
|
||||||
if (enabled.value) {
|
if (enabled.value) {
|
||||||
renderer.setLayers(layers);
|
await renderer.setLayers(layers);
|
||||||
} else {
|
} else {
|
||||||
renderer.setLayers([]);
|
await renderer.setLayers([]);
|
||||||
}
|
}
|
||||||
renderer.render();
|
await renderer.render();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -560,7 +560,7 @@ async function preprocess(item: (typeof items)['value'][number]): Promise<void>
|
||||||
|
|
||||||
await renderer.setLayers(preset.layers);
|
await renderer.setLayers(preset.layers);
|
||||||
|
|
||||||
renderer.render();
|
await renderer.render();
|
||||||
|
|
||||||
file = await new Promise<Blob>((resolve) => {
|
file = await new Promise<Blob>((resolve) => {
|
||||||
canvas.toBlob((blob) => {
|
canvas.toBlob((blob) => {
|
||||||
|
|
|
@ -80,7 +80,7 @@ onMounted(() => {
|
||||||
|
|
||||||
await renderer.setLayers(props.preset.layers);
|
await renderer.setLayers(props.preset.layers);
|
||||||
|
|
||||||
renderer.render();
|
await renderer.render();
|
||||||
}, { immediate: true });
|
}, { immediate: true });
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -95,7 +95,7 @@ onUnmounted(() => {
|
||||||
watch(() => props.preset, async () => {
|
watch(() => props.preset, async () => {
|
||||||
if (renderer != null) {
|
if (renderer != null) {
|
||||||
await renderer.setLayers(props.preset.layers);
|
await renderer.setLayers(props.preset.layers);
|
||||||
renderer.render();
|
await renderer.render();
|
||||||
}
|
}
|
||||||
}, { deep: true });
|
}, { deep: true });
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -27,7 +27,7 @@ export function defineImageEffectorFx<ID extends string, PS extends ImageEffecto
|
||||||
export type ImageEffectorFx<ID extends string = string, PS extends ImageEffectorFxParamDefs = ImageEffectorFxParamDefs, US extends string[] = string[]> = {
|
export type ImageEffectorFx<ID extends string = string, PS extends ImageEffectorFxParamDefs = ImageEffectorFxParamDefs, US extends string[] = string[]> = {
|
||||||
id: ID;
|
id: ID;
|
||||||
name: string;
|
name: string;
|
||||||
shader: string;
|
shader: string | (() => Promise<string>);
|
||||||
uniforms: US;
|
uniforms: US;
|
||||||
params: PS,
|
params: PS,
|
||||||
main: (ctx: {
|
main: (ctx: {
|
||||||
|
@ -196,14 +196,27 @@ export class ImageEffector<IEX extends ReadonlyArray<ImageEffectorFx<any, any, a
|
||||||
return shaderProgram;
|
return shaderProgram;
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderLayer(layer: ImageEffectorLayer, preTexture: WebGLTexture) {
|
private async renderLayer(layer: ImageEffectorLayer, preTexture: WebGLTexture) {
|
||||||
const gl = this.gl;
|
const gl = this.gl;
|
||||||
|
|
||||||
const fx = this.fxs.find(fx => fx.id === layer.fxId);
|
const fx = this.fxs.find(fx => fx.id === layer.fxId);
|
||||||
if (fx == null) return;
|
if (fx == null) return;
|
||||||
|
|
||||||
const cachedShader = this.shaderCache.get(fx.id);
|
const cachedShader = this.shaderCache.get(fx.id);
|
||||||
const shaderProgram = cachedShader ?? this.initShaderProgram(`#version 300 es
|
let shaderProgram: WebGLProgram;
|
||||||
|
|
||||||
|
if (cachedShader != null) {
|
||||||
|
shaderProgram = cachedShader;
|
||||||
|
} else {
|
||||||
|
let shaderSource: string;
|
||||||
|
|
||||||
|
if (typeof fx.shader === 'string') {
|
||||||
|
shaderSource = fx.shader;
|
||||||
|
} else {
|
||||||
|
shaderSource = await fx.shader();
|
||||||
|
}
|
||||||
|
|
||||||
|
shaderProgram = this.initShaderProgram(`#version 300 es
|
||||||
in vec2 position;
|
in vec2 position;
|
||||||
out vec2 in_uv;
|
out vec2 in_uv;
|
||||||
|
|
||||||
|
@ -211,7 +224,9 @@ export class ImageEffector<IEX extends ReadonlyArray<ImageEffectorFx<any, any, a
|
||||||
in_uv = (position + 1.0) / 2.0;
|
in_uv = (position + 1.0) / 2.0;
|
||||||
gl_Position = vec4(position, 0.0, 1.0);
|
gl_Position = vec4(position, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
`, fx.shader);
|
`, shaderSource);
|
||||||
|
}
|
||||||
|
|
||||||
if (cachedShader == null) {
|
if (cachedShader == null) {
|
||||||
this.shaderCache.set(fx.id, shaderProgram);
|
this.shaderCache.set(fx.id, shaderProgram);
|
||||||
}
|
}
|
||||||
|
@ -230,7 +245,7 @@ export class ImageEffector<IEX extends ReadonlyArray<ImageEffectorFx<any, any, a
|
||||||
gl: gl,
|
gl: gl,
|
||||||
program: shaderProgram,
|
program: shaderProgram,
|
||||||
params: Object.fromEntries(
|
params: Object.fromEntries(
|
||||||
Object.entries(fx.params).map(([key, param]) => {
|
Object.entries(fx.params as ImageEffectorFxParamDefs).map(([key, param]) => {
|
||||||
return [key, layer.params[key] ?? param.default];
|
return [key, layer.params[key] ?? param.default];
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
@ -238,7 +253,7 @@ export class ImageEffector<IEX extends ReadonlyArray<ImageEffectorFx<any, any, a
|
||||||
width: this.renderWidth,
|
width: this.renderWidth,
|
||||||
height: this.renderHeight,
|
height: this.renderHeight,
|
||||||
textures: Object.fromEntries(
|
textures: Object.fromEntries(
|
||||||
Object.entries(fx.params).map(([k, v]) => {
|
Object.entries(fx.params as ImageEffectorFxParamDefs).map(([k, v]) => {
|
||||||
if (v.type !== 'texture') return [k, null];
|
if (v.type !== 'texture') return [k, null];
|
||||||
const param = getValue<typeof v.type>(layer.params, k);
|
const param = getValue<typeof v.type>(layer.params, k);
|
||||||
if (param == null) return [k, null];
|
if (param == null) return [k, null];
|
||||||
|
@ -250,7 +265,7 @@ export class ImageEffector<IEX extends ReadonlyArray<ImageEffectorFx<any, any, a
|
||||||
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public async render() {
|
||||||
const gl = this.gl;
|
const gl = this.gl;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -291,7 +306,7 @@ export class ImageEffector<IEX extends ReadonlyArray<ImageEffectorFx<any, any, a
|
||||||
gl.bindFramebuffer(gl.FRAMEBUFFER, resultFrameBuffer);
|
gl.bindFramebuffer(gl.FRAMEBUFFER, resultFrameBuffer);
|
||||||
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, resultTexture, 0);
|
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, resultTexture, 0);
|
||||||
|
|
||||||
this.renderLayer(layer, preTexture);
|
await this.renderLayer(layer, preTexture);
|
||||||
|
|
||||||
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
||||||
|
|
||||||
|
|
|
@ -34,11 +34,11 @@ export const FXS = [
|
||||||
FX_stripe,
|
FX_stripe,
|
||||||
FX_polkadot,
|
FX_polkadot,
|
||||||
FX_checker,
|
FX_checker,
|
||||||
] as const satisfies ImageEffectorFx<string, any>[];
|
] satisfies ReadonlyArray<ImageEffectorFx<string, any, any>>;
|
||||||
|
|
||||||
export const WATERMARK_FXS = [
|
export const WATERMARK_FXS = [
|
||||||
FX_watermarkPlacement,
|
FX_watermarkPlacement,
|
||||||
FX_stripe,
|
FX_stripe,
|
||||||
FX_polkadot,
|
FX_polkadot,
|
||||||
FX_checker,
|
FX_checker,
|
||||||
] as const satisfies ImageEffectorFx<string, any>[];
|
] satisfies ReadonlyArray<ImageEffectorFx<string, any, any>>;
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#version 300 es
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
const float PI = 3.141592653589793;
|
||||||
|
const float TWO_PI = 6.283185307179586;
|
||||||
|
const float HALF_PI = 1.5707963267948966;
|
||||||
|
|
||||||
|
in vec2 in_uv;
|
||||||
|
uniform sampler2D in_texture;
|
||||||
|
uniform vec2 in_resolution;
|
||||||
|
uniform float u_angle;
|
||||||
|
uniform float u_scale;
|
||||||
|
uniform vec3 u_color;
|
||||||
|
uniform float u_opacity;
|
||||||
|
out vec4 out_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 in_color = texture(in_texture, in_uv);
|
||||||
|
float x_ratio = max(in_resolution.x / in_resolution.y, 1.0);
|
||||||
|
float y_ratio = max(in_resolution.y / in_resolution.x, 1.0);
|
||||||
|
|
||||||
|
float angle = -(u_angle * PI);
|
||||||
|
vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio);
|
||||||
|
vec2 rotatedUV = vec2(
|
||||||
|
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
|
||||||
|
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
|
||||||
|
);
|
||||||
|
|
||||||
|
float fmodResult = mod(floor(u_scale * rotatedUV.x) + floor(u_scale * rotatedUV.y), 2.0);
|
||||||
|
float fin = max(sign(fmodResult), 0.0);
|
||||||
|
|
||||||
|
out_color = vec4(
|
||||||
|
mix(in_color.r, u_color.r, fin * u_opacity),
|
||||||
|
mix(in_color.g, u_color.g, fin * u_opacity),
|
||||||
|
mix(in_color.b, u_color.b, fin * u_opacity),
|
||||||
|
in_color.a
|
||||||
|
);
|
||||||
|
}
|
|
@ -6,50 +6,10 @@
|
||||||
import { defineImageEffectorFx } from '../ImageEffector.js';
|
import { defineImageEffectorFx } from '../ImageEffector.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
const shader = `#version 300 es
|
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
const float PI = 3.141592653589793;
|
|
||||||
const float TWO_PI = 6.283185307179586;
|
|
||||||
const float HALF_PI = 1.5707963267948966;
|
|
||||||
|
|
||||||
in vec2 in_uv;
|
|
||||||
uniform sampler2D in_texture;
|
|
||||||
uniform vec2 in_resolution;
|
|
||||||
uniform float u_angle;
|
|
||||||
uniform float u_scale;
|
|
||||||
uniform vec3 u_color;
|
|
||||||
uniform float u_opacity;
|
|
||||||
out vec4 out_color;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec4 in_color = texture(in_texture, in_uv);
|
|
||||||
float x_ratio = max(in_resolution.x / in_resolution.y, 1.0);
|
|
||||||
float y_ratio = max(in_resolution.y / in_resolution.x, 1.0);
|
|
||||||
|
|
||||||
float angle = -(u_angle * PI);
|
|
||||||
vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio);
|
|
||||||
vec2 rotatedUV = vec2(
|
|
||||||
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
|
|
||||||
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
|
|
||||||
);
|
|
||||||
|
|
||||||
float fmodResult = mod(floor(u_scale * rotatedUV.x) + floor(u_scale * rotatedUV.y), 2.0);
|
|
||||||
float fin = max(sign(fmodResult), 0.0);
|
|
||||||
|
|
||||||
out_color = vec4(
|
|
||||||
mix(in_color.r, u_color.r, fin * u_opacity),
|
|
||||||
mix(in_color.g, u_color.g, fin * u_opacity),
|
|
||||||
mix(in_color.b, u_color.b, fin * u_opacity),
|
|
||||||
in_color.a
|
|
||||||
);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const FX_checker = defineImageEffectorFx({
|
export const FX_checker = defineImageEffectorFx({
|
||||||
id: 'checker' as const,
|
id: 'checker' as const,
|
||||||
name: i18n.ts._imageEffector._fxs.checker,
|
name: i18n.ts._imageEffector._fxs.checker,
|
||||||
shader,
|
shader: () => import('./checker.glsl?raw').then(m => m.default),
|
||||||
uniforms: ['angle', 'scale', 'color', 'opacity'] as const,
|
uniforms: ['angle', 'scale', 'color', 'opacity'] as const,
|
||||||
params: {
|
params: {
|
||||||
angle: {
|
angle: {
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#version 300 es
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
in vec2 in_uv;
|
||||||
|
uniform sampler2D in_texture;
|
||||||
|
uniform vec2 in_resolution;
|
||||||
|
out vec4 out_color;
|
||||||
|
uniform float u_amount;
|
||||||
|
uniform float u_start;
|
||||||
|
uniform bool u_normalize;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
int samples = 64;
|
||||||
|
float r_strength = 1.0;
|
||||||
|
float g_strength = 1.5;
|
||||||
|
float b_strength = 2.0;
|
||||||
|
|
||||||
|
vec2 size = vec2(in_resolution.x, in_resolution.y);
|
||||||
|
|
||||||
|
vec4 accumulator = vec4(0.0);
|
||||||
|
float normalisedValue = length((in_uv - 0.5) * 2.0);
|
||||||
|
float strength = clamp((normalisedValue - u_start) * (1.0 / (1.0 - u_start)), 0.0, 1.0);
|
||||||
|
|
||||||
|
vec2 vector = (u_normalize ? normalize(in_uv - vec2(0.5)) : in_uv - vec2(0.5));
|
||||||
|
vec2 velocity = vector * strength * u_amount;
|
||||||
|
|
||||||
|
vec2 rOffset = -vector * strength * (u_amount * r_strength);
|
||||||
|
vec2 gOffset = -vector * strength * (u_amount * g_strength);
|
||||||
|
vec2 bOffset = -vector * strength * (u_amount * b_strength);
|
||||||
|
|
||||||
|
for (int i = 0; i < samples; i++) {
|
||||||
|
accumulator.r += texture(in_texture, in_uv + rOffset).r;
|
||||||
|
rOffset -= velocity / float(samples);
|
||||||
|
|
||||||
|
accumulator.g += texture(in_texture, in_uv + gOffset).g;
|
||||||
|
gOffset -= velocity / float(samples);
|
||||||
|
|
||||||
|
accumulator.b += texture(in_texture, in_uv + bOffset).b;
|
||||||
|
bOffset -= velocity / float(samples);
|
||||||
|
}
|
||||||
|
|
||||||
|
out_color = vec4(vec3(accumulator / float(samples)), 1.0);
|
||||||
|
}
|
|
@ -6,55 +6,10 @@
|
||||||
import { defineImageEffectorFx } from '../ImageEffector.js';
|
import { defineImageEffectorFx } from '../ImageEffector.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
const shader = `#version 300 es
|
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
in vec2 in_uv;
|
|
||||||
uniform sampler2D in_texture;
|
|
||||||
uniform vec2 in_resolution;
|
|
||||||
out vec4 out_color;
|
|
||||||
uniform float u_amount;
|
|
||||||
uniform float u_start;
|
|
||||||
uniform bool u_normalize;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
int samples = 64;
|
|
||||||
float r_strength = 1.0;
|
|
||||||
float g_strength = 1.5;
|
|
||||||
float b_strength = 2.0;
|
|
||||||
|
|
||||||
vec2 size = vec2(in_resolution.x, in_resolution.y);
|
|
||||||
|
|
||||||
vec4 accumulator = vec4(0.0);
|
|
||||||
float normalisedValue = length((in_uv - 0.5) * 2.0);
|
|
||||||
float strength = clamp((normalisedValue - u_start) * (1.0 / (1.0 - u_start)), 0.0, 1.0);
|
|
||||||
|
|
||||||
vec2 vector = (u_normalize ? normalize(in_uv - vec2(0.5)) : in_uv - vec2(0.5));
|
|
||||||
vec2 velocity = vector * strength * u_amount;
|
|
||||||
|
|
||||||
vec2 rOffset = -vector * strength * (u_amount * r_strength);
|
|
||||||
vec2 gOffset = -vector * strength * (u_amount * g_strength);
|
|
||||||
vec2 bOffset = -vector * strength * (u_amount * b_strength);
|
|
||||||
|
|
||||||
for (int i = 0; i < samples; i++) {
|
|
||||||
accumulator.r += texture(in_texture, in_uv + rOffset).r;
|
|
||||||
rOffset -= velocity / float(samples);
|
|
||||||
|
|
||||||
accumulator.g += texture(in_texture, in_uv + gOffset).g;
|
|
||||||
gOffset -= velocity / float(samples);
|
|
||||||
|
|
||||||
accumulator.b += texture(in_texture, in_uv + bOffset).b;
|
|
||||||
bOffset -= velocity / float(samples);
|
|
||||||
}
|
|
||||||
|
|
||||||
out_color = vec4(vec3(accumulator / float(samples)), 1.0);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const FX_chromaticAberration = defineImageEffectorFx({
|
export const FX_chromaticAberration = defineImageEffectorFx({
|
||||||
id: 'chromaticAberration' as const,
|
id: 'chromaticAberration' as const,
|
||||||
name: i18n.ts._imageEffector._fxs.chromaticAberration,
|
name: i18n.ts._imageEffector._fxs.chromaticAberration,
|
||||||
shader,
|
shader: () => import('./chromaticAberration.glsl?raw').then(m => m.default),
|
||||||
uniforms: ['amount', 'start', 'normalize'] as const,
|
uniforms: ['amount', 'start', 'normalize'] as const,
|
||||||
params: {
|
params: {
|
||||||
normalize: {
|
normalize: {
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#version 300 es
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
in vec2 in_uv;
|
||||||
|
uniform sampler2D in_texture;
|
||||||
|
uniform vec2 in_resolution;
|
||||||
|
uniform float u_max;
|
||||||
|
uniform float u_min;
|
||||||
|
out vec4 out_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 in_color = texture(in_texture, in_uv);
|
||||||
|
float r = min(max(in_color.r, u_min), u_max);
|
||||||
|
float g = min(max(in_color.g, u_min), u_max);
|
||||||
|
float b = min(max(in_color.b, u_min), u_max);
|
||||||
|
out_color = vec4(r, g, b, in_color.a);
|
||||||
|
}
|
|
@ -6,29 +6,10 @@
|
||||||
import { defineImageEffectorFx } from '../ImageEffector.js';
|
import { defineImageEffectorFx } from '../ImageEffector.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
const shader = `#version 300 es
|
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
in vec2 in_uv;
|
|
||||||
uniform sampler2D in_texture;
|
|
||||||
uniform vec2 in_resolution;
|
|
||||||
uniform float u_max;
|
|
||||||
uniform float u_min;
|
|
||||||
out vec4 out_color;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec4 in_color = texture(in_texture, in_uv);
|
|
||||||
float r = min(max(in_color.r, u_min), u_max);
|
|
||||||
float g = min(max(in_color.g, u_min), u_max);
|
|
||||||
float b = min(max(in_color.b, u_min), u_max);
|
|
||||||
out_color = vec4(r, g, b, in_color.a);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const FX_colorClamp = defineImageEffectorFx({
|
export const FX_colorClamp = defineImageEffectorFx({
|
||||||
id: 'colorClamp' as const,
|
id: 'colorClamp' as const,
|
||||||
name: i18n.ts._imageEffector._fxs.colorClamp,
|
name: i18n.ts._imageEffector._fxs.colorClamp,
|
||||||
shader,
|
shader: () => import('./colorClamp.glsl?raw').then(m => m.default),
|
||||||
uniforms: ['max', 'min'] as const,
|
uniforms: ['max', 'min'] as const,
|
||||||
params: {
|
params: {
|
||||||
max: {
|
max: {
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#version 300 es
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
in vec2 in_uv;
|
||||||
|
uniform sampler2D in_texture;
|
||||||
|
uniform vec2 in_resolution;
|
||||||
|
uniform float u_rMax;
|
||||||
|
uniform float u_rMin;
|
||||||
|
uniform float u_gMax;
|
||||||
|
uniform float u_gMin;
|
||||||
|
uniform float u_bMax;
|
||||||
|
uniform float u_bMin;
|
||||||
|
out vec4 out_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 in_color = texture(in_texture, in_uv);
|
||||||
|
float r = min(max(in_color.r, u_rMin), u_rMax);
|
||||||
|
float g = min(max(in_color.g, u_gMin), u_gMax);
|
||||||
|
float b = min(max(in_color.b, u_bMin), u_bMax);
|
||||||
|
out_color = vec4(r, g, b, in_color.a);
|
||||||
|
}
|
|
@ -6,33 +6,10 @@
|
||||||
import { defineImageEffectorFx } from '../ImageEffector.js';
|
import { defineImageEffectorFx } from '../ImageEffector.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
const shader = `#version 300 es
|
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
in vec2 in_uv;
|
|
||||||
uniform sampler2D in_texture;
|
|
||||||
uniform vec2 in_resolution;
|
|
||||||
uniform float u_rMax;
|
|
||||||
uniform float u_rMin;
|
|
||||||
uniform float u_gMax;
|
|
||||||
uniform float u_gMin;
|
|
||||||
uniform float u_bMax;
|
|
||||||
uniform float u_bMin;
|
|
||||||
out vec4 out_color;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec4 in_color = texture(in_texture, in_uv);
|
|
||||||
float r = min(max(in_color.r, u_rMin), u_rMax);
|
|
||||||
float g = min(max(in_color.g, u_gMin), u_gMax);
|
|
||||||
float b = min(max(in_color.b, u_bMin), u_bMax);
|
|
||||||
out_color = vec4(r, g, b, in_color.a);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const FX_colorClampAdvanced = defineImageEffectorFx({
|
export const FX_colorClampAdvanced = defineImageEffectorFx({
|
||||||
id: 'colorClampAdvanced' as const,
|
id: 'colorClampAdvanced' as const,
|
||||||
name: i18n.ts._imageEffector._fxs.colorClampAdvanced,
|
name: i18n.ts._imageEffector._fxs.colorClampAdvanced,
|
||||||
shader,
|
shader: () => import('./colorClampAdvanced.glsl?raw').then(m => m.default),
|
||||||
uniforms: ['rMax', 'rMin', 'gMax', 'gMin', 'bMax', 'bMin'] as const,
|
uniforms: ['rMax', 'rMin', 'gMax', 'gMin', 'bMax', 'bMin'] as const,
|
||||||
params: {
|
params: {
|
||||||
rMax: {
|
rMax: {
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#version 300 es
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
in vec2 in_uv;
|
||||||
|
uniform sampler2D in_texture;
|
||||||
|
uniform vec2 in_resolution;
|
||||||
|
uniform float u_phase;
|
||||||
|
uniform float u_frequency;
|
||||||
|
uniform float u_strength;
|
||||||
|
uniform int u_direction; // 0: vertical, 1: horizontal
|
||||||
|
out vec4 out_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
float v = u_direction == 0 ?
|
||||||
|
sin(u_phase + in_uv.y * u_frequency) * u_strength :
|
||||||
|
sin(u_phase + in_uv.x * u_frequency) * u_strength;
|
||||||
|
vec4 in_color = u_direction == 0 ?
|
||||||
|
texture(in_texture, vec2(in_uv.x + v, in_uv.y)) :
|
||||||
|
texture(in_texture, vec2(in_uv.x, in_uv.y + v));
|
||||||
|
out_color = in_color;
|
||||||
|
}
|
|
@ -6,33 +6,10 @@
|
||||||
import { defineImageEffectorFx } from '../ImageEffector.js';
|
import { defineImageEffectorFx } from '../ImageEffector.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
const shader = `#version 300 es
|
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
in vec2 in_uv;
|
|
||||||
uniform sampler2D in_texture;
|
|
||||||
uniform vec2 in_resolution;
|
|
||||||
uniform float u_phase;
|
|
||||||
uniform float u_frequency;
|
|
||||||
uniform float u_strength;
|
|
||||||
uniform int u_direction; // 0: vertical, 1: horizontal
|
|
||||||
out vec4 out_color;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
float v = u_direction == 0 ?
|
|
||||||
sin(u_phase + in_uv.y * u_frequency) * u_strength :
|
|
||||||
sin(u_phase + in_uv.x * u_frequency) * u_strength;
|
|
||||||
vec4 in_color = u_direction == 0 ?
|
|
||||||
texture(in_texture, vec2(in_uv.x + v, in_uv.y)) :
|
|
||||||
texture(in_texture, vec2(in_uv.x, in_uv.y + v));
|
|
||||||
out_color = in_color;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const FX_distort = defineImageEffectorFx({
|
export const FX_distort = defineImageEffectorFx({
|
||||||
id: 'distort' as const,
|
id: 'distort' as const,
|
||||||
name: i18n.ts._imageEffector._fxs.distort,
|
name: i18n.ts._imageEffector._fxs.distort,
|
||||||
shader,
|
shader: () => import('./distort.glsl?raw').then(m => m.default),
|
||||||
uniforms: ['phase', 'frequency', 'strength', 'direction'] as const,
|
uniforms: ['phase', 'frequency', 'strength', 'direction'] as const,
|
||||||
params: {
|
params: {
|
||||||
direction: {
|
direction: {
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#version 300 es
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
in vec2 in_uv;
|
||||||
|
uniform sampler2D in_texture;
|
||||||
|
uniform vec2 in_resolution;
|
||||||
|
uniform int u_amount;
|
||||||
|
uniform float u_shiftStrengths[128];
|
||||||
|
uniform float u_shiftOrigins[128];
|
||||||
|
uniform float u_shiftHeights[128];
|
||||||
|
uniform float u_channelShift;
|
||||||
|
out vec4 out_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
float v = 0.0;
|
||||||
|
|
||||||
|
for (int i = 0; i < u_amount; i++) {
|
||||||
|
if (in_uv.y > (u_shiftOrigins[i] - u_shiftHeights[i]) && in_uv.y < (u_shiftOrigins[i] + u_shiftHeights[i])) {
|
||||||
|
v += u_shiftStrengths[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float r = texture(in_texture, vec2(in_uv.x + (v * (1.0 + u_channelShift)), in_uv.y)).r;
|
||||||
|
float g = texture(in_texture, vec2(in_uv.x + v, in_uv.y)).g;
|
||||||
|
float b = texture(in_texture, vec2(in_uv.x + (v * (1.0 + (u_channelShift / 2.0))), in_uv.y)).b;
|
||||||
|
float a = texture(in_texture, vec2(in_uv.x + v, in_uv.y)).a;
|
||||||
|
out_color = vec4(r, g, b, a);
|
||||||
|
}
|
|
@ -7,40 +7,10 @@ import seedrandom from 'seedrandom';
|
||||||
import { defineImageEffectorFx } from '../ImageEffector.js';
|
import { defineImageEffectorFx } from '../ImageEffector.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
const shader = `#version 300 es
|
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
in vec2 in_uv;
|
|
||||||
uniform sampler2D in_texture;
|
|
||||||
uniform vec2 in_resolution;
|
|
||||||
uniform int u_amount;
|
|
||||||
uniform float u_shiftStrengths[128];
|
|
||||||
uniform float u_shiftOrigins[128];
|
|
||||||
uniform float u_shiftHeights[128];
|
|
||||||
uniform float u_channelShift;
|
|
||||||
out vec4 out_color;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
float v = 0.0;
|
|
||||||
|
|
||||||
for (int i = 0; i < u_amount; i++) {
|
|
||||||
if (in_uv.y > (u_shiftOrigins[i] - u_shiftHeights[i]) && in_uv.y < (u_shiftOrigins[i] + u_shiftHeights[i])) {
|
|
||||||
v += u_shiftStrengths[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float r = texture(in_texture, vec2(in_uv.x + (v * (1.0 + u_channelShift)), in_uv.y)).r;
|
|
||||||
float g = texture(in_texture, vec2(in_uv.x + v, in_uv.y)).g;
|
|
||||||
float b = texture(in_texture, vec2(in_uv.x + (v * (1.0 + (u_channelShift / 2.0))), in_uv.y)).b;
|
|
||||||
float a = texture(in_texture, vec2(in_uv.x + v, in_uv.y)).a;
|
|
||||||
out_color = vec4(r, g, b, a);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const FX_glitch = defineImageEffectorFx({
|
export const FX_glitch = defineImageEffectorFx({
|
||||||
id: 'glitch' as const,
|
id: 'glitch' as const,
|
||||||
name: i18n.ts._imageEffector._fxs.glitch,
|
name: i18n.ts._imageEffector._fxs.glitch,
|
||||||
shader,
|
shader: () => import('./glitch.glsl?raw').then(m => m.default),
|
||||||
uniforms: ['amount', 'channelShift'] as const,
|
uniforms: ['amount', 'channelShift'] as const,
|
||||||
params: {
|
params: {
|
||||||
amount: {
|
amount: {
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#version 300 es
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
in vec2 in_uv;
|
||||||
|
uniform sampler2D in_texture;
|
||||||
|
uniform vec2 in_resolution;
|
||||||
|
out vec4 out_color;
|
||||||
|
|
||||||
|
float getBrightness(vec4 color) {
|
||||||
|
return (color.r + color.g + color.b) / 3.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 in_color = texture(in_texture, in_uv);
|
||||||
|
float brightness = getBrightness(in_color);
|
||||||
|
out_color = vec4(brightness, brightness, brightness, in_color.a);
|
||||||
|
}
|
|
@ -6,29 +6,10 @@
|
||||||
import { defineImageEffectorFx } from '../ImageEffector.js';
|
import { defineImageEffectorFx } from '../ImageEffector.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
const shader = `#version 300 es
|
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
in vec2 in_uv;
|
|
||||||
uniform sampler2D in_texture;
|
|
||||||
uniform vec2 in_resolution;
|
|
||||||
out vec4 out_color;
|
|
||||||
|
|
||||||
float getBrightness(vec4 color) {
|
|
||||||
return (color.r + color.g + color.b) / 3.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec4 in_color = texture(in_texture, in_uv);
|
|
||||||
float brightness = getBrightness(in_color);
|
|
||||||
out_color = vec4(brightness, brightness, brightness, in_color.a);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const FX_grayscale = defineImageEffectorFx({
|
export const FX_grayscale = defineImageEffectorFx({
|
||||||
id: 'grayscale' as const,
|
id: 'grayscale' as const,
|
||||||
name: i18n.ts._imageEffector._fxs.grayscale,
|
name: i18n.ts._imageEffector._fxs.grayscale,
|
||||||
shader,
|
shader: () => import('./grayscale.glsl?raw').then(m => m.default),
|
||||||
uniforms: [] as const,
|
uniforms: [] as const,
|
||||||
params: {
|
params: {
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#version 300 es
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
in vec2 in_uv;
|
||||||
|
uniform sampler2D in_texture;
|
||||||
|
uniform vec2 in_resolution;
|
||||||
|
uniform bool u_r;
|
||||||
|
uniform bool u_g;
|
||||||
|
uniform bool u_b;
|
||||||
|
out vec4 out_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 in_color = texture(in_texture, in_uv);
|
||||||
|
out_color.r = u_r ? 1.0 - in_color.r : in_color.r;
|
||||||
|
out_color.g = u_g ? 1.0 - in_color.g : in_color.g;
|
||||||
|
out_color.b = u_b ? 1.0 - in_color.b : in_color.b;
|
||||||
|
out_color.a = in_color.a;
|
||||||
|
}
|
|
@ -6,30 +6,10 @@
|
||||||
import { defineImageEffectorFx } from '../ImageEffector.js';
|
import { defineImageEffectorFx } from '../ImageEffector.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
const shader = `#version 300 es
|
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
in vec2 in_uv;
|
|
||||||
uniform sampler2D in_texture;
|
|
||||||
uniform vec2 in_resolution;
|
|
||||||
uniform bool u_r;
|
|
||||||
uniform bool u_g;
|
|
||||||
uniform bool u_b;
|
|
||||||
out vec4 out_color;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec4 in_color = texture(in_texture, in_uv);
|
|
||||||
out_color.r = u_r ? 1.0 - in_color.r : in_color.r;
|
|
||||||
out_color.g = u_g ? 1.0 - in_color.g : in_color.g;
|
|
||||||
out_color.b = u_b ? 1.0 - in_color.b : in_color.b;
|
|
||||||
out_color.a = in_color.a;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const FX_invert = defineImageEffectorFx({
|
export const FX_invert = defineImageEffectorFx({
|
||||||
id: 'invert' as const,
|
id: 'invert' as const,
|
||||||
name: i18n.ts._imageEffector._fxs.invert,
|
name: i18n.ts._imageEffector._fxs.invert,
|
||||||
shader,
|
shader: () => import('./invert.glsl?raw').then(m => m.default),
|
||||||
uniforms: ['r', 'g', 'b'] as const,
|
uniforms: ['r', 'g', 'b'] as const,
|
||||||
params: {
|
params: {
|
||||||
r: {
|
r: {
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#version 300 es
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
in vec2 in_uv;
|
||||||
|
uniform sampler2D in_texture;
|
||||||
|
uniform vec2 in_resolution;
|
||||||
|
uniform int u_h;
|
||||||
|
uniform int u_v;
|
||||||
|
out vec4 out_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 uv = in_uv;
|
||||||
|
if (u_h == -1 && in_uv.x > 0.5) {
|
||||||
|
uv.x = 1.0 - uv.x;
|
||||||
|
}
|
||||||
|
if (u_h == 1 && in_uv.x < 0.5) {
|
||||||
|
uv.x = 1.0 - uv.x;
|
||||||
|
}
|
||||||
|
if (u_v == -1 && in_uv.y > 0.5) {
|
||||||
|
uv.y = 1.0 - uv.y;
|
||||||
|
}
|
||||||
|
if (u_v == 1 && in_uv.y < 0.5) {
|
||||||
|
uv.y = 1.0 - uv.y;
|
||||||
|
}
|
||||||
|
out_color = texture(in_texture, uv);
|
||||||
|
}
|
|
@ -6,38 +6,10 @@
|
||||||
import { defineImageEffectorFx } from '../ImageEffector.js';
|
import { defineImageEffectorFx } from '../ImageEffector.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
const shader = `#version 300 es
|
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
in vec2 in_uv;
|
|
||||||
uniform sampler2D in_texture;
|
|
||||||
uniform vec2 in_resolution;
|
|
||||||
uniform int u_h;
|
|
||||||
uniform int u_v;
|
|
||||||
out vec4 out_color;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec2 uv = in_uv;
|
|
||||||
if (u_h == -1 && in_uv.x > 0.5) {
|
|
||||||
uv.x = 1.0 - uv.x;
|
|
||||||
}
|
|
||||||
if (u_h == 1 && in_uv.x < 0.5) {
|
|
||||||
uv.x = 1.0 - uv.x;
|
|
||||||
}
|
|
||||||
if (u_v == -1 && in_uv.y > 0.5) {
|
|
||||||
uv.y = 1.0 - uv.y;
|
|
||||||
}
|
|
||||||
if (u_v == 1 && in_uv.y < 0.5) {
|
|
||||||
uv.y = 1.0 - uv.y;
|
|
||||||
}
|
|
||||||
out_color = texture(in_texture, uv);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const FX_mirror = defineImageEffectorFx({
|
export const FX_mirror = defineImageEffectorFx({
|
||||||
id: 'mirror' as const,
|
id: 'mirror' as const,
|
||||||
name: i18n.ts._imageEffector._fxs.mirror,
|
name: i18n.ts._imageEffector._fxs.mirror,
|
||||||
shader,
|
shader: () => import('./mirror.glsl?raw').then(m => m.default),
|
||||||
uniforms: ['h', 'v'] as const,
|
uniforms: ['h', 'v'] as const,
|
||||||
params: {
|
params: {
|
||||||
h: {
|
h: {
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#version 300 es
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
const float PI = 3.141592653589793;
|
||||||
|
const float TWO_PI = 6.283185307179586;
|
||||||
|
const float HALF_PI = 1.5707963267948966;
|
||||||
|
|
||||||
|
in vec2 in_uv;
|
||||||
|
uniform sampler2D in_texture;
|
||||||
|
uniform vec2 in_resolution;
|
||||||
|
uniform float u_angle;
|
||||||
|
uniform float u_scale;
|
||||||
|
uniform float u_major_radius;
|
||||||
|
uniform float u_major_opacity;
|
||||||
|
uniform float u_minor_divisions;
|
||||||
|
uniform float u_minor_radius;
|
||||||
|
uniform float u_minor_opacity;
|
||||||
|
uniform vec3 u_color;
|
||||||
|
out vec4 out_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 in_color = texture(in_texture, in_uv);
|
||||||
|
float x_ratio = max(in_resolution.x / in_resolution.y, 1.0);
|
||||||
|
float y_ratio = max(in_resolution.y / in_resolution.x, 1.0);
|
||||||
|
|
||||||
|
float angle = -(u_angle * PI);
|
||||||
|
vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio);
|
||||||
|
vec2 rotatedUV = vec2(
|
||||||
|
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
|
||||||
|
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
|
||||||
|
);
|
||||||
|
|
||||||
|
float major_modX = mod(rotatedUV.x, (1.0 / u_scale));
|
||||||
|
float major_modY = mod(rotatedUV.y, (1.0 / u_scale));
|
||||||
|
float major_threshold = ((u_major_radius / 2.0) / u_scale);
|
||||||
|
if (
|
||||||
|
length(vec2(major_modX, major_modY)) < major_threshold ||
|
||||||
|
length(vec2((1.0 / u_scale) - major_modX, major_modY)) < major_threshold ||
|
||||||
|
length(vec2(major_modX, (1.0 / u_scale) - major_modY)) < major_threshold ||
|
||||||
|
length(vec2((1.0 / u_scale) - major_modX, (1.0 / u_scale) - major_modY)) < major_threshold
|
||||||
|
) {
|
||||||
|
out_color = vec4(
|
||||||
|
mix(in_color.r, u_color.r, u_major_opacity),
|
||||||
|
mix(in_color.g, u_color.g, u_major_opacity),
|
||||||
|
mix(in_color.b, u_color.b, u_major_opacity),
|
||||||
|
in_color.a
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float minor_modX = mod(rotatedUV.x, (1.0 / u_scale / u_minor_divisions));
|
||||||
|
float minor_modY = mod(rotatedUV.y, (1.0 / u_scale / u_minor_divisions));
|
||||||
|
float minor_threshold = ((u_minor_radius / 2.0) / (u_minor_divisions * u_scale));
|
||||||
|
if (
|
||||||
|
length(vec2(minor_modX, minor_modY)) < minor_threshold ||
|
||||||
|
length(vec2((1.0 / u_scale / u_minor_divisions) - minor_modX, minor_modY)) < minor_threshold ||
|
||||||
|
length(vec2(minor_modX, (1.0 / u_scale / u_minor_divisions) - minor_modY)) < minor_threshold ||
|
||||||
|
length(vec2((1.0 / u_scale / u_minor_divisions) - minor_modX, (1.0 / u_scale / u_minor_divisions) - minor_modY)) < minor_threshold
|
||||||
|
) {
|
||||||
|
out_color = vec4(
|
||||||
|
mix(in_color.r, u_color.r, u_minor_opacity),
|
||||||
|
mix(in_color.g, u_color.g, u_minor_opacity),
|
||||||
|
mix(in_color.b, u_color.b, u_minor_opacity),
|
||||||
|
in_color.a
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_color = in_color;
|
||||||
|
}
|
|
@ -6,82 +6,10 @@
|
||||||
import { defineImageEffectorFx } from '../ImageEffector.js';
|
import { defineImageEffectorFx } from '../ImageEffector.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
const shader = `#version 300 es
|
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
const float PI = 3.141592653589793;
|
|
||||||
const float TWO_PI = 6.283185307179586;
|
|
||||||
const float HALF_PI = 1.5707963267948966;
|
|
||||||
|
|
||||||
in vec2 in_uv;
|
|
||||||
uniform sampler2D in_texture;
|
|
||||||
uniform vec2 in_resolution;
|
|
||||||
uniform float u_angle;
|
|
||||||
uniform float u_scale;
|
|
||||||
uniform float u_major_radius;
|
|
||||||
uniform float u_major_opacity;
|
|
||||||
uniform float u_minor_divisions;
|
|
||||||
uniform float u_minor_radius;
|
|
||||||
uniform float u_minor_opacity;
|
|
||||||
uniform vec3 u_color;
|
|
||||||
out vec4 out_color;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec4 in_color = texture(in_texture, in_uv);
|
|
||||||
float x_ratio = max(in_resolution.x / in_resolution.y, 1.0);
|
|
||||||
float y_ratio = max(in_resolution.y / in_resolution.x, 1.0);
|
|
||||||
|
|
||||||
float angle = -(u_angle * PI);
|
|
||||||
vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio);
|
|
||||||
vec2 rotatedUV = vec2(
|
|
||||||
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
|
|
||||||
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
|
|
||||||
);
|
|
||||||
|
|
||||||
float major_modX = mod(rotatedUV.x, (1.0 / u_scale));
|
|
||||||
float major_modY = mod(rotatedUV.y, (1.0 / u_scale));
|
|
||||||
float major_threshold = ((u_major_radius / 2.0) / u_scale);
|
|
||||||
if (
|
|
||||||
length(vec2(major_modX, major_modY)) < major_threshold ||
|
|
||||||
length(vec2((1.0 / u_scale) - major_modX, major_modY)) < major_threshold ||
|
|
||||||
length(vec2(major_modX, (1.0 / u_scale) - major_modY)) < major_threshold ||
|
|
||||||
length(vec2((1.0 / u_scale) - major_modX, (1.0 / u_scale) - major_modY)) < major_threshold
|
|
||||||
) {
|
|
||||||
out_color = vec4(
|
|
||||||
mix(in_color.r, u_color.r, u_major_opacity),
|
|
||||||
mix(in_color.g, u_color.g, u_major_opacity),
|
|
||||||
mix(in_color.b, u_color.b, u_major_opacity),
|
|
||||||
in_color.a
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
float minor_modX = mod(rotatedUV.x, (1.0 / u_scale / u_minor_divisions));
|
|
||||||
float minor_modY = mod(rotatedUV.y, (1.0 / u_scale / u_minor_divisions));
|
|
||||||
float minor_threshold = ((u_minor_radius / 2.0) / (u_minor_divisions * u_scale));
|
|
||||||
if (
|
|
||||||
length(vec2(minor_modX, minor_modY)) < minor_threshold ||
|
|
||||||
length(vec2((1.0 / u_scale / u_minor_divisions) - minor_modX, minor_modY)) < minor_threshold ||
|
|
||||||
length(vec2(minor_modX, (1.0 / u_scale / u_minor_divisions) - minor_modY)) < minor_threshold ||
|
|
||||||
length(vec2((1.0 / u_scale / u_minor_divisions) - minor_modX, (1.0 / u_scale / u_minor_divisions) - minor_modY)) < minor_threshold
|
|
||||||
) {
|
|
||||||
out_color = vec4(
|
|
||||||
mix(in_color.r, u_color.r, u_minor_opacity),
|
|
||||||
mix(in_color.g, u_color.g, u_minor_opacity),
|
|
||||||
mix(in_color.b, u_color.b, u_minor_opacity),
|
|
||||||
in_color.a
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
out_color = in_color;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const FX_polkadot = defineImageEffectorFx({
|
export const FX_polkadot = defineImageEffectorFx({
|
||||||
id: 'polkadot' as const,
|
id: 'polkadot' as const,
|
||||||
name: i18n.ts._imageEffector._fxs.polkadot,
|
name: i18n.ts._imageEffector._fxs.polkadot,
|
||||||
shader,
|
shader: () => import('./polkadot.glsl?raw').then(m => m.default),
|
||||||
uniforms: ['angle', 'scale', 'major_radius', 'major_opacity', 'minor_divisions', 'minor_radius', 'minor_opacity', 'color'] as const,
|
uniforms: ['angle', 'scale', 'major_radius', 'major_opacity', 'minor_divisions', 'minor_radius', 'minor_opacity', 'color'] as const,
|
||||||
params: {
|
params: {
|
||||||
angle: {
|
angle: {
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#version 300 es
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
const float PI = 3.141592653589793;
|
||||||
|
const float TWO_PI = 6.283185307179586;
|
||||||
|
const float HALF_PI = 1.5707963267948966;
|
||||||
|
|
||||||
|
in vec2 in_uv;
|
||||||
|
uniform sampler2D in_texture;
|
||||||
|
uniform vec2 in_resolution;
|
||||||
|
uniform float u_angle;
|
||||||
|
uniform float u_frequency;
|
||||||
|
uniform float u_phase;
|
||||||
|
uniform float u_threshold;
|
||||||
|
uniform vec3 u_color;
|
||||||
|
uniform float u_opacity;
|
||||||
|
out vec4 out_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 in_color = texture(in_texture, in_uv);
|
||||||
|
float x_ratio = max(in_resolution.x / in_resolution.y, 1.0);
|
||||||
|
float y_ratio = max(in_resolution.y / in_resolution.x, 1.0);
|
||||||
|
|
||||||
|
float angle = -(u_angle * PI);
|
||||||
|
vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio);
|
||||||
|
vec2 rotatedUV = vec2(
|
||||||
|
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
|
||||||
|
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
|
||||||
|
);
|
||||||
|
|
||||||
|
float phase = u_phase * TWO_PI;
|
||||||
|
float value = (1.0 + sin((rotatedUV.x * u_frequency - HALF_PI) + phase)) / 2.0;
|
||||||
|
value = value < u_threshold ? 1.0 : 0.0;
|
||||||
|
out_color = vec4(
|
||||||
|
mix(in_color.r, u_color.r, value * u_opacity),
|
||||||
|
mix(in_color.g, u_color.g, value * u_opacity),
|
||||||
|
mix(in_color.b, u_color.b, value * u_opacity),
|
||||||
|
in_color.a
|
||||||
|
);
|
||||||
|
}
|
|
@ -6,52 +6,10 @@
|
||||||
import { defineImageEffectorFx } from '../ImageEffector.js';
|
import { defineImageEffectorFx } from '../ImageEffector.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
const shader = `#version 300 es
|
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
const float PI = 3.141592653589793;
|
|
||||||
const float TWO_PI = 6.283185307179586;
|
|
||||||
const float HALF_PI = 1.5707963267948966;
|
|
||||||
|
|
||||||
in vec2 in_uv;
|
|
||||||
uniform sampler2D in_texture;
|
|
||||||
uniform vec2 in_resolution;
|
|
||||||
uniform float u_angle;
|
|
||||||
uniform float u_frequency;
|
|
||||||
uniform float u_phase;
|
|
||||||
uniform float u_threshold;
|
|
||||||
uniform vec3 u_color;
|
|
||||||
uniform float u_opacity;
|
|
||||||
out vec4 out_color;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec4 in_color = texture(in_texture, in_uv);
|
|
||||||
float x_ratio = max(in_resolution.x / in_resolution.y, 1.0);
|
|
||||||
float y_ratio = max(in_resolution.y / in_resolution.x, 1.0);
|
|
||||||
|
|
||||||
float angle = -(u_angle * PI);
|
|
||||||
vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio);
|
|
||||||
vec2 rotatedUV = vec2(
|
|
||||||
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
|
|
||||||
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
|
|
||||||
);
|
|
||||||
|
|
||||||
float phase = u_phase * TWO_PI;
|
|
||||||
float value = (1.0 + sin((rotatedUV.x * u_frequency - HALF_PI) + phase)) / 2.0;
|
|
||||||
value = value < u_threshold ? 1.0 : 0.0;
|
|
||||||
out_color = vec4(
|
|
||||||
mix(in_color.r, u_color.r, value * u_opacity),
|
|
||||||
mix(in_color.g, u_color.g, value * u_opacity),
|
|
||||||
mix(in_color.b, u_color.b, value * u_opacity),
|
|
||||||
in_color.a
|
|
||||||
);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const FX_stripe = defineImageEffectorFx({
|
export const FX_stripe = defineImageEffectorFx({
|
||||||
id: 'stripe' as const,
|
id: 'stripe' as const,
|
||||||
name: i18n.ts._imageEffector._fxs.stripe,
|
name: i18n.ts._imageEffector._fxs.stripe,
|
||||||
shader,
|
shader: () => import('./stripe.glsl?raw').then(m => m.default),
|
||||||
uniforms: ['angle', 'frequency', 'phase', 'threshold', 'color', 'opacity'] as const,
|
uniforms: ['angle', 'frequency', 'phase', 'threshold', 'color', 'opacity'] as const,
|
||||||
params: {
|
params: {
|
||||||
angle: {
|
angle: {
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#version 300 es
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
in vec2 in_uv;
|
||||||
|
uniform sampler2D in_texture;
|
||||||
|
uniform vec2 in_resolution;
|
||||||
|
uniform float u_r;
|
||||||
|
uniform float u_g;
|
||||||
|
uniform float u_b;
|
||||||
|
out vec4 out_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 in_color = texture(in_texture, in_uv);
|
||||||
|
float r = in_color.r < u_r ? 0.0 : 1.0;
|
||||||
|
float g = in_color.g < u_g ? 0.0 : 1.0;
|
||||||
|
float b = in_color.b < u_b ? 0.0 : 1.0;
|
||||||
|
out_color = vec4(r, g, b, in_color.a);
|
||||||
|
}
|
|
@ -6,30 +6,10 @@
|
||||||
import { defineImageEffectorFx } from '../ImageEffector.js';
|
import { defineImageEffectorFx } from '../ImageEffector.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
const shader = `#version 300 es
|
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
in vec2 in_uv;
|
|
||||||
uniform sampler2D in_texture;
|
|
||||||
uniform vec2 in_resolution;
|
|
||||||
uniform float u_r;
|
|
||||||
uniform float u_g;
|
|
||||||
uniform float u_b;
|
|
||||||
out vec4 out_color;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec4 in_color = texture(in_texture, in_uv);
|
|
||||||
float r = in_color.r < u_r ? 0.0 : 1.0;
|
|
||||||
float g = in_color.g < u_g ? 0.0 : 1.0;
|
|
||||||
float b = in_color.b < u_b ? 0.0 : 1.0;
|
|
||||||
out_color = vec4(r, g, b, in_color.a);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const FX_threshold = defineImageEffectorFx({
|
export const FX_threshold = defineImageEffectorFx({
|
||||||
id: 'threshold' as const,
|
id: 'threshold' as const,
|
||||||
name: i18n.ts._imageEffector._fxs.threshold,
|
name: i18n.ts._imageEffector._fxs.threshold,
|
||||||
shader,
|
shader: () => import('./threshold.glsl?raw').then(m => m.default),
|
||||||
uniforms: ['r', 'g', 'b'] as const,
|
uniforms: ['r', 'g', 'b'] as const,
|
||||||
params: {
|
params: {
|
||||||
r: {
|
r: {
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#version 300 es
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
const float PI = 3.141592653589793;
|
||||||
|
const float TWO_PI = 6.283185307179586;
|
||||||
|
const float HALF_PI = 1.5707963267948966;
|
||||||
|
|
||||||
|
in vec2 in_uv;
|
||||||
|
uniform sampler2D in_texture;
|
||||||
|
uniform vec2 in_resolution;
|
||||||
|
uniform sampler2D u_texture_watermark;
|
||||||
|
uniform vec2 u_resolution_watermark;
|
||||||
|
uniform float u_scale;
|
||||||
|
uniform float u_angle;
|
||||||
|
uniform float u_opacity;
|
||||||
|
uniform bool u_repeat;
|
||||||
|
uniform int u_alignX; // 0: left, 1: center, 2: right
|
||||||
|
uniform int u_alignY; // 0: top, 1: center, 2: bottom
|
||||||
|
uniform int u_fitMode; // 0: contain, 1: cover
|
||||||
|
out vec4 out_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 in_color = texture(in_texture, in_uv);
|
||||||
|
float in_x_ratio = max(in_resolution.x / in_resolution.y, 1.0);
|
||||||
|
float in_y_ratio = max(in_resolution.y / in_resolution.x, 1.0);
|
||||||
|
|
||||||
|
bool contain = u_fitMode == 0;
|
||||||
|
|
||||||
|
float x_ratio = u_resolution_watermark.x / in_resolution.x;
|
||||||
|
float y_ratio = u_resolution_watermark.y / in_resolution.y;
|
||||||
|
|
||||||
|
float aspect_ratio = contain ?
|
||||||
|
(min(x_ratio, y_ratio) / max(x_ratio, y_ratio)) :
|
||||||
|
(max(x_ratio, y_ratio) / min(x_ratio, y_ratio));
|
||||||
|
|
||||||
|
float x_scale = contain ?
|
||||||
|
(x_ratio > y_ratio ? 1.0 * u_scale : aspect_ratio * u_scale) :
|
||||||
|
(x_ratio > y_ratio ? aspect_ratio * u_scale : 1.0 * u_scale);
|
||||||
|
|
||||||
|
float y_scale = contain ?
|
||||||
|
(y_ratio > x_ratio ? 1.0 * u_scale : aspect_ratio * u_scale) :
|
||||||
|
(y_ratio > x_ratio ? aspect_ratio * u_scale : 1.0 * u_scale);
|
||||||
|
|
||||||
|
float x_offset = u_alignX == 0 ? x_scale / 2.0 : u_alignX == 2 ? 1.0 - (x_scale / 2.0) : 0.5;
|
||||||
|
float y_offset = u_alignY == 0 ? y_scale / 2.0 : u_alignY == 2 ? 1.0 - (y_scale / 2.0) : 0.5;
|
||||||
|
|
||||||
|
float angle = -(u_angle * PI);
|
||||||
|
vec2 center = vec2(x_offset, y_offset);
|
||||||
|
//vec2 centeredUv = (in_uv - center) * vec2(in_x_ratio, in_y_ratio);
|
||||||
|
vec2 centeredUv = (in_uv - center);
|
||||||
|
vec2 rotatedUV = vec2(
|
||||||
|
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
|
||||||
|
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
|
||||||
|
) + center;
|
||||||
|
|
||||||
|
// trim
|
||||||
|
if (!u_repeat) {
|
||||||
|
bool isInside = rotatedUV.x > x_offset - (x_scale / 2.0) && rotatedUV.x < x_offset + (x_scale / 2.0) &&
|
||||||
|
rotatedUV.y > y_offset - (y_scale / 2.0) && rotatedUV.y < y_offset + (y_scale / 2.0);
|
||||||
|
if (!isInside) {
|
||||||
|
out_color = in_color;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 watermark_color = texture(u_texture_watermark, vec2(
|
||||||
|
(rotatedUV.x - (x_offset - (x_scale / 2.0))) / x_scale,
|
||||||
|
(rotatedUV.y - (y_offset - (y_scale / 2.0))) / y_scale
|
||||||
|
));
|
||||||
|
|
||||||
|
out_color.r = mix(in_color.r, watermark_color.r, u_opacity * watermark_color.a);
|
||||||
|
out_color.g = mix(in_color.g, watermark_color.g, u_opacity * watermark_color.a);
|
||||||
|
out_color.b = mix(in_color.b, watermark_color.b, u_opacity * watermark_color.a);
|
||||||
|
out_color.a = in_color.a * (1.0 - u_opacity * watermark_color.a) + watermark_color.a * u_opacity;
|
||||||
|
}
|
|
@ -5,87 +5,10 @@
|
||||||
|
|
||||||
import { defineImageEffectorFx } from '../ImageEffector.js';
|
import { defineImageEffectorFx } from '../ImageEffector.js';
|
||||||
|
|
||||||
const shader = `#version 300 es
|
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
const float PI = 3.141592653589793;
|
|
||||||
const float TWO_PI = 6.283185307179586;
|
|
||||||
const float HALF_PI = 1.5707963267948966;
|
|
||||||
|
|
||||||
in vec2 in_uv;
|
|
||||||
uniform sampler2D in_texture;
|
|
||||||
uniform vec2 in_resolution;
|
|
||||||
uniform sampler2D u_texture_watermark;
|
|
||||||
uniform vec2 u_resolution_watermark;
|
|
||||||
uniform float u_scale;
|
|
||||||
uniform float u_angle;
|
|
||||||
uniform float u_opacity;
|
|
||||||
uniform bool u_repeat;
|
|
||||||
uniform int u_alignX; // 0: left, 1: center, 2: right
|
|
||||||
uniform int u_alignY; // 0: top, 1: center, 2: bottom
|
|
||||||
uniform int u_fitMode; // 0: contain, 1: cover
|
|
||||||
out vec4 out_color;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec4 in_color = texture(in_texture, in_uv);
|
|
||||||
float in_x_ratio = max(in_resolution.x / in_resolution.y, 1.0);
|
|
||||||
float in_y_ratio = max(in_resolution.y / in_resolution.x, 1.0);
|
|
||||||
|
|
||||||
bool contain = u_fitMode == 0;
|
|
||||||
|
|
||||||
float x_ratio = u_resolution_watermark.x / in_resolution.x;
|
|
||||||
float y_ratio = u_resolution_watermark.y / in_resolution.y;
|
|
||||||
|
|
||||||
float aspect_ratio = contain ?
|
|
||||||
(min(x_ratio, y_ratio) / max(x_ratio, y_ratio)) :
|
|
||||||
(max(x_ratio, y_ratio) / min(x_ratio, y_ratio));
|
|
||||||
|
|
||||||
float x_scale = contain ?
|
|
||||||
(x_ratio > y_ratio ? 1.0 * u_scale : aspect_ratio * u_scale) :
|
|
||||||
(x_ratio > y_ratio ? aspect_ratio * u_scale : 1.0 * u_scale);
|
|
||||||
|
|
||||||
float y_scale = contain ?
|
|
||||||
(y_ratio > x_ratio ? 1.0 * u_scale : aspect_ratio * u_scale) :
|
|
||||||
(y_ratio > x_ratio ? aspect_ratio * u_scale : 1.0 * u_scale);
|
|
||||||
|
|
||||||
float x_offset = u_alignX == 0 ? x_scale / 2.0 : u_alignX == 2 ? 1.0 - (x_scale / 2.0) : 0.5;
|
|
||||||
float y_offset = u_alignY == 0 ? y_scale / 2.0 : u_alignY == 2 ? 1.0 - (y_scale / 2.0) : 0.5;
|
|
||||||
|
|
||||||
float angle = -(u_angle * PI);
|
|
||||||
vec2 center = vec2(x_offset, y_offset);
|
|
||||||
//vec2 centeredUv = (in_uv - center) * vec2(in_x_ratio, in_y_ratio);
|
|
||||||
vec2 centeredUv = (in_uv - center);
|
|
||||||
vec2 rotatedUV = vec2(
|
|
||||||
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
|
|
||||||
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
|
|
||||||
) + center;
|
|
||||||
|
|
||||||
// trim
|
|
||||||
if (!u_repeat) {
|
|
||||||
bool isInside = rotatedUV.x > x_offset - (x_scale / 2.0) && rotatedUV.x < x_offset + (x_scale / 2.0) &&
|
|
||||||
rotatedUV.y > y_offset - (y_scale / 2.0) && rotatedUV.y < y_offset + (y_scale / 2.0);
|
|
||||||
if (!isInside) {
|
|
||||||
out_color = in_color;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 watermark_color = texture(u_texture_watermark, vec2(
|
|
||||||
(rotatedUV.x - (x_offset - (x_scale / 2.0))) / x_scale,
|
|
||||||
(rotatedUV.y - (y_offset - (y_scale / 2.0))) / y_scale
|
|
||||||
));
|
|
||||||
|
|
||||||
out_color.r = mix(in_color.r, watermark_color.r, u_opacity * watermark_color.a);
|
|
||||||
out_color.g = mix(in_color.g, watermark_color.g, u_opacity * watermark_color.a);
|
|
||||||
out_color.b = mix(in_color.b, watermark_color.b, u_opacity * watermark_color.a);
|
|
||||||
out_color.a = in_color.a * (1.0 - u_opacity * watermark_color.a) + watermark_color.a * u_opacity;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const FX_watermarkPlacement = defineImageEffectorFx({
|
export const FX_watermarkPlacement = defineImageEffectorFx({
|
||||||
id: 'watermarkPlacement' as const,
|
id: 'watermarkPlacement' as const,
|
||||||
name: '(internal)',
|
name: '(internal)',
|
||||||
shader,
|
shader: () => import('./watermarkPlacement.glsl?raw').then(m => m.default),
|
||||||
uniforms: ['texture_watermark', 'resolution_watermark', 'scale', 'angle', 'opacity', 'repeat', 'alignX', 'alignY', 'fitMode'] as const,
|
uniforms: ['texture_watermark', 'resolution_watermark', 'scale', 'angle', 'opacity', 'repeat', 'alignX', 'alignY', 'fitMode'] as const,
|
||||||
params: {
|
params: {
|
||||||
cover: {
|
cover: {
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#version 300 es
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
in vec2 in_uv;
|
||||||
|
uniform sampler2D in_texture;
|
||||||
|
uniform vec2 in_resolution;
|
||||||
|
uniform vec2 u_pos;
|
||||||
|
uniform float u_frequency;
|
||||||
|
uniform bool u_thresholdEnabled;
|
||||||
|
uniform float u_threshold;
|
||||||
|
uniform float u_maskSize;
|
||||||
|
uniform bool u_black;
|
||||||
|
out vec4 out_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 in_color = texture(in_texture, in_uv);
|
||||||
|
float angle = atan(-u_pos.y + (in_uv.y), -u_pos.x + (in_uv.x));
|
||||||
|
float t = (1.0 + sin(angle * u_frequency)) / 2.0;
|
||||||
|
if (u_thresholdEnabled) t = t < u_threshold ? 1.0 : 0.0;
|
||||||
|
float d = distance(in_uv * vec2(2.0, 2.0), u_pos * vec2(2.0, 2.0));
|
||||||
|
float mask = d < u_maskSize ? 0.0 : ((d - u_maskSize) * (1.0 + (u_maskSize * 2.0)));
|
||||||
|
out_color = vec4(
|
||||||
|
mix(in_color.r, u_black ? 0.0 : 1.0, t * mask),
|
||||||
|
mix(in_color.g, u_black ? 0.0 : 1.0, t * mask),
|
||||||
|
mix(in_color.b, u_black ? 0.0 : 1.0, t * mask),
|
||||||
|
in_color.a
|
||||||
|
);
|
||||||
|
}
|
|
@ -6,40 +6,10 @@
|
||||||
import { defineImageEffectorFx } from '../ImageEffector.js';
|
import { defineImageEffectorFx } from '../ImageEffector.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
const shader = `#version 300 es
|
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
in vec2 in_uv;
|
|
||||||
uniform sampler2D in_texture;
|
|
||||||
uniform vec2 in_resolution;
|
|
||||||
uniform vec2 u_pos;
|
|
||||||
uniform float u_frequency;
|
|
||||||
uniform bool u_thresholdEnabled;
|
|
||||||
uniform float u_threshold;
|
|
||||||
uniform float u_maskSize;
|
|
||||||
uniform bool u_black;
|
|
||||||
out vec4 out_color;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec4 in_color = texture(in_texture, in_uv);
|
|
||||||
float angle = atan(-u_pos.y + (in_uv.y), -u_pos.x + (in_uv.x));
|
|
||||||
float t = (1.0 + sin(angle * u_frequency)) / 2.0;
|
|
||||||
if (u_thresholdEnabled) t = t < u_threshold ? 1.0 : 0.0;
|
|
||||||
float d = distance(in_uv * vec2(2.0, 2.0), u_pos * vec2(2.0, 2.0));
|
|
||||||
float mask = d < u_maskSize ? 0.0 : ((d - u_maskSize) * (1.0 + (u_maskSize * 2.0)));
|
|
||||||
out_color = vec4(
|
|
||||||
mix(in_color.r, u_black ? 0.0 : 1.0, t * mask),
|
|
||||||
mix(in_color.g, u_black ? 0.0 : 1.0, t * mask),
|
|
||||||
mix(in_color.b, u_black ? 0.0 : 1.0, t * mask),
|
|
||||||
in_color.a
|
|
||||||
);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const FX_zoomLines = defineImageEffectorFx({
|
export const FX_zoomLines = defineImageEffectorFx({
|
||||||
id: 'zoomLines' as const,
|
id: 'zoomLines' as const,
|
||||||
name: i18n.ts._imageEffector._fxs.zoomLines,
|
name: i18n.ts._imageEffector._fxs.zoomLines,
|
||||||
shader,
|
shader: () => import('./zoomLines.glsl?raw').then(m => m.default),
|
||||||
uniforms: ['pos', 'frequency', 'thresholdEnabled', 'threshold', 'maskSize', 'black'] as const,
|
uniforms: ['pos', 'frequency', 'thresholdEnabled', 'threshold', 'maskSize', 'black'] as const,
|
||||||
params: {
|
params: {
|
||||||
x: {
|
x: {
|
||||||
|
|
|
@ -163,11 +163,11 @@ export class WatermarkRenderer {
|
||||||
public async setLayers(layers: WatermarkPreset['layers']) {
|
public async setLayers(layers: WatermarkPreset['layers']) {
|
||||||
this.layers = layers;
|
this.layers = layers;
|
||||||
await this.effector.setLayers(this.makeImageEffectorLayers());
|
await this.effector.setLayers(this.makeImageEffectorLayers());
|
||||||
this.render();
|
await this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(): void {
|
public async render(): Promise<void> {
|
||||||
this.effector.render();
|
await this.effector.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue