fix: シェーダーの読み込みが完了してからレンダリングを行うように
This commit is contained in:
parent
afcc37d886
commit
e06f37a7d4
|
@ -20,6 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div :class="$style.container">
|
<div :class="$style.container">
|
||||||
<div :class="$style.preview">
|
<div :class="$style.preview">
|
||||||
<canvas ref="canvasEl" :class="$style.previewCanvas"></canvas>
|
<canvas ref="canvasEl" :class="$style.previewCanvas"></canvas>
|
||||||
|
<MkLoading v-if="canvasLoading" :class="$style.previewSpinner"/>
|
||||||
<div :class="$style.previewContainer">
|
<div :class="$style.previewContainer">
|
||||||
<div class="_acrylic" :class="$style.previewTitle">{{ i18n.ts.preview }}</div>
|
<div class="_acrylic" :class="$style.previewTitle">{{ i18n.ts.preview }}</div>
|
||||||
<div class="_acrylic" :class="$style.previewControls">
|
<div class="_acrylic" :class="$style.previewControls">
|
||||||
|
@ -74,6 +75,8 @@ const emit = defineEmits<{
|
||||||
|
|
||||||
const dialog = useTemplateRef('dialog');
|
const dialog = useTemplateRef('dialog');
|
||||||
|
|
||||||
|
const canvasLoading = ref(false);
|
||||||
|
|
||||||
async function cancel() {
|
async function cancel() {
|
||||||
if (layers.length > 0) {
|
if (layers.length > 0) {
|
||||||
const { canceled } = await os.confirm({
|
const { canceled } = await os.confirm({
|
||||||
|
@ -91,7 +94,9 @@ const layers = reactive<ImageEffectorLayer[]>([]);
|
||||||
|
|
||||||
watch(layers, async () => {
|
watch(layers, async () => {
|
||||||
if (renderer != null) {
|
if (renderer != null) {
|
||||||
renderer.setLayers(layers);
|
canvasLoading.value = true;
|
||||||
|
await renderer.setLayers(layers);
|
||||||
|
canvasLoading.value = false;
|
||||||
}
|
}
|
||||||
}, { deep: true });
|
}, { deep: true });
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div :class="$style.container">
|
<div :class="$style.container">
|
||||||
<div :class="$style.preview">
|
<div :class="$style.preview">
|
||||||
<canvas ref="canvasEl" :class="$style.previewCanvas"></canvas>
|
<canvas ref="canvasEl" :class="$style.previewCanvas"></canvas>
|
||||||
|
<MkLoading v-if="canvasLoading" :class="$style.previewSpinner"/>
|
||||||
<div :class="$style.previewContainer">
|
<div :class="$style.previewContainer">
|
||||||
<div class="_acrylic" :class="$style.previewTitle">{{ i18n.ts.preview }}</div>
|
<div class="_acrylic" :class="$style.previewTitle">{{ i18n.ts.preview }}</div>
|
||||||
<div v-if="props.image == null" class="_acrylic" :class="$style.previewControls">
|
<div v-if="props.image == null" class="_acrylic" :class="$style.previewControls">
|
||||||
|
@ -89,6 +90,8 @@ import { genId } from '@/utility/id.js';
|
||||||
|
|
||||||
const $i = ensureSignin();
|
const $i = ensureSignin();
|
||||||
|
|
||||||
|
const canvasLoading = ref(true);
|
||||||
|
|
||||||
function createTextLayer(): WatermarkPreset['layers'][number] {
|
function createTextLayer(): WatermarkPreset['layers'][number] {
|
||||||
return {
|
return {
|
||||||
id: genId(),
|
id: genId(),
|
||||||
|
@ -232,6 +235,13 @@ let imageBitmap: ImageBitmap | null = null;
|
||||||
async function initRenderer() {
|
async function initRenderer() {
|
||||||
if (canvasEl.value == null) return;
|
if (canvasEl.value == null) return;
|
||||||
|
|
||||||
|
canvasLoading.value = true;
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
sampleImage_3_2_loading,
|
||||||
|
sampleImage_2_3_loading,
|
||||||
|
]);
|
||||||
|
|
||||||
if (sampleImageType.value === '3_2') {
|
if (sampleImageType.value === '3_2') {
|
||||||
renderer = new WatermarkRenderer({
|
renderer = new WatermarkRenderer({
|
||||||
canvas: canvasEl.value,
|
canvas: canvasEl.value,
|
||||||
|
@ -270,7 +280,9 @@ async function initRenderer() {
|
||||||
|
|
||||||
await renderer!.setLayers(preset.layers);
|
await renderer!.setLayers(preset.layers);
|
||||||
|
|
||||||
renderer!.render();
|
await renderer!.render();
|
||||||
|
|
||||||
|
canvasLoading.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
|
|
@ -196,40 +196,35 @@ export class ImageEffector<IEX extends ReadonlyArray<ImageEffectorFx<any, any, a
|
||||||
return shaderProgram;
|
return shaderProgram;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async getOrLoadShaderProgram(fx: ImageEffectorFx): Promise<WebGLProgram> {
|
||||||
|
let shaderProgram = this.shaderCache.get(fx.id);
|
||||||
|
if (shaderProgram) return shaderProgram;
|
||||||
|
|
||||||
|
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;
|
||||||
|
out vec2 in_uv;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
in_uv = (position + 1.0) / 2.0;
|
||||||
|
gl_Position = vec4(position, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
`, shaderSource);
|
||||||
|
this.shaderCache.set(fx.id, shaderProgram);
|
||||||
|
return shaderProgram;
|
||||||
|
}
|
||||||
|
|
||||||
private async 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 shaderProgram = await this.getOrLoadShaderProgram(fx);
|
||||||
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;
|
|
||||||
out vec2 in_uv;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
in_uv = (position + 1.0) / 2.0;
|
|
||||||
gl_Position = vec4(position, 0.0, 1.0);
|
|
||||||
}
|
|
||||||
`, shaderSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cachedShader == null) {
|
|
||||||
this.shaderCache.set(fx.id, shaderProgram);
|
|
||||||
}
|
|
||||||
|
|
||||||
gl.useProgram(shaderProgram);
|
gl.useProgram(shaderProgram);
|
||||||
|
|
||||||
|
@ -268,6 +263,13 @@ export class ImageEffector<IEX extends ReadonlyArray<ImageEffectorFx<any, any, a
|
||||||
public async render() {
|
public async render() {
|
||||||
const gl = this.gl;
|
const gl = this.gl;
|
||||||
|
|
||||||
|
// 全レイヤーのshaderロードを事前に完了させる
|
||||||
|
await Promise.all(this.layers.map(async (layer) => {
|
||||||
|
const fx = this.fxs.find(fx => fx.id === layer.fxId);
|
||||||
|
if (!fx) return;
|
||||||
|
await this.getOrLoadShaderProgram(fx);
|
||||||
|
}));
|
||||||
|
|
||||||
{
|
{
|
||||||
gl.activeTexture(gl.TEXTURE0);
|
gl.activeTexture(gl.TEXTURE0);
|
||||||
gl.bindTexture(gl.TEXTURE_2D, this.originalImageTexture);
|
gl.bindTexture(gl.TEXTURE_2D, this.originalImageTexture);
|
||||||
|
@ -359,7 +361,7 @@ export class ImageEffector<IEX extends ReadonlyArray<ImageEffectorFx<any, any, a
|
||||||
this.paramTextures.delete(k);
|
this.paramTextures.delete(k);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.render();
|
await this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
public changeResolution(width: number, height: number) {
|
public changeResolution(width: number, height: number) {
|
||||||
|
|
Loading…
Reference in New Issue