diff --git a/locales/index.d.ts b/locales/index.d.ts index a316930c7e..0343c4ae99 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -12168,6 +12168,10 @@ export interface Locale extends ILocale { * 点グリッド */ "dottedGrid": string; + /** + * チェッカー + */ + "checker": string; }; }; } diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 59d15cb51a..d5f58010fe 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -3260,3 +3260,4 @@ _imageEffector: zoomLines: "集中線" stripe: "ストライプ" dottedGrid: "点グリッド" + checker: "チェッカー" diff --git a/packages/frontend/src/utility/image-effector/fxs.ts b/packages/frontend/src/utility/image-effector/fxs.ts index d17684d11e..a113ec3b2e 100644 --- a/packages/frontend/src/utility/image-effector/fxs.ts +++ b/packages/frontend/src/utility/image-effector/fxs.ts @@ -3,6 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ +import { FX_checker } from './fxs/checker.js'; import { FX_chromaticAberration } from './fxs/chromaticAberration.js'; import { FX_colorClamp } from './fxs/colorClamp.js'; import { FX_colorClampAdvanced } from './fxs/colorClampAdvanced.js'; @@ -32,4 +33,5 @@ export const FXS = [ FX_zoomLines, FX_stripe, FX_dottedGrid, + FX_checker, ] as const satisfies ImageEffectorFx[]; diff --git a/packages/frontend/src/utility/image-effector/fxs/checker.ts b/packages/frontend/src/utility/image-effector/fxs/checker.ts new file mode 100644 index 0000000000..d79c31c292 --- /dev/null +++ b/packages/frontend/src/utility/image-effector/fxs/checker.ts @@ -0,0 +1,87 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { defineImageEffectorFx } from '../ImageEffector.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 bool u_black; +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_black ? 0.0 : 1.0, fin * u_opacity), + mix(in_color.g, u_black ? 0.0 : 1.0, fin * u_opacity), + mix(in_color.b, u_black ? 0.0 : 1.0, fin * u_opacity), + in_color.a + ); +} +`; + +export const FX_checker = defineImageEffectorFx({ + id: 'checker' as const, + name: i18n.ts._imageEffector._fxs.checker, + shader, + uniforms: ['angle', 'scale', 'black', 'opacity'] as const, + params: { + angle: { + type: 'number' as const, + default: 0, + min: -1.0, + max: 1.0, + step: 0.01, + }, + scale: { + type: 'number' as const, + default: 3.0, + min: 1.0, + max: 10.0, + step: 0.1, + }, + black: { + type: 'boolean' as const, + default: false, + }, + opacity: { + type: 'number' as const, + default: 0.5, + min: 0.0, + max: 1.0, + step: 0.01, + }, + }, + main: ({ gl, u, params }) => { + gl.uniform1f(u.angle, params.angle / 2); + gl.uniform1f(u.scale, params.scale * params.scale); + gl.uniform1i(u.black, params.black ? 1 : 0); + gl.uniform1f(u.opacity, params.opacity); + }, +});