diff options
author | Javiya Vivekkumar Dineshbhai <vivek.javiya@collabora.com> | 2024-07-01 15:41:04 +0530 |
---|---|---|
committer | Szymon Kłos <szymon.klos@collabora.com> | 2024-07-03 23:26:36 +0200 |
commit | 776a0116b77175bf416625dc2a6913fdc8bcea19 (patch) | |
tree | d4752fb1253509ea62dd63d2014a87bfb2fd24b1 | |
parent | Convert SlideShowPresenter to TS (diff) | |
download | online-776a0116b77175bf416625dc2a6913fdc8bcea19.tar.gz online-776a0116b77175bf416625dc2a6913fdc8bcea19.zip |
Add 2d Fade transition
Signed-off-by: Javiya Vivekkumar Dineshbhai <vivek.javiya@collabora.com>
Change-Id: I4745b6e8d747e68cc8e0264a534ba9bf87d90df8
-rw-r--r-- | browser/Makefile.am | 4 | ||||
-rw-r--r-- | browser/src/slideshow/transition/FadeTransition.ts | 104 | ||||
-rw-r--r-- | browser/src/slideshow/transition/Transition2d.ts | 225 | ||||
-rw-r--r-- | browser/src/slideshow/transition/shader/2dVertexShader.glsl | 9 | ||||
-rw-r--r-- | browser/src/slideshow/transition/shader/fadeFragmentShader.glsl | 36 |
5 files changed, 378 insertions, 0 deletions
diff --git a/browser/Makefile.am b/browser/Makefile.am index b9895112e7..0c1769a364 100644 --- a/browser/Makefile.am +++ b/browser/Makefile.am @@ -411,6 +411,8 @@ COOL_JS_LST =\ src/control/Ruler.js \ src/control/VRuler.ts \ src/slideshow/SlideShowPresenter.ts \ + src/slideshow/transition/Transition2d.ts \ + src/slideshow/transition/FadeTransition.ts \ src/dom/PosAnimation.js \ src/map/anim/Map.PanAnimation.js \ src/dom/PosAnimation.Timer.js \ @@ -844,6 +846,8 @@ pot: src/control/jsdialog/Widget.Timefield.js \ src/control/jsdialog/Widget.TreeView.js \ src/slideshow/SlideShowPresenter.ts \ + src/slideshow/transition/Transition2d.ts \ + src/slideshow/transition/FadeTransition.ts \ src/core/Socket.js \ src/core/Debug.js \ src/docstate.js \ diff --git a/browser/src/slideshow/transition/FadeTransition.ts b/browser/src/slideshow/transition/FadeTransition.ts new file mode 100644 index 0000000000..06ae6f132f --- /dev/null +++ b/browser/src/slideshow/transition/FadeTransition.ts @@ -0,0 +1,104 @@ +/* + * Copyright the Collabora Online contributors. + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +class FadeTransition extends Transition2d { + private effectTransition: number = 0; + constructor( + canvas: HTMLCanvasElement, + vertexShaderSource: string, + fragmentShaderSource: string, + image1: HTMLImageElement, + image2: HTMLImageElement, + ) { + super(canvas, vertexShaderSource, fragmentShaderSource, image1, image2); + this.prepareTransition(); + this.animationTime = 1500; + } + + public renderUniformValue(): void { + this.gl.uniform1i( + this.gl.getUniformLocation(this.program, 'effectType'), + this.effectTransition, + ); + } + + public start(selectedEffectType: number): void { + this.effectTransition = selectedEffectType; + this.startTransition(); + } +} + +app.definitions.FadeTransition = function () { + const canvas = document.getElementById( + 'fullscreen-canvas', + ) as HTMLCanvasElement; + const vertexShaderSource = `#version 300 es +in vec4 a_position; +in vec2 a_texCoord; +out vec2 v_texCoord; + +void main() { + gl_Position = a_position; + v_texCoord = a_texCoord; +} +`; + + const fragmentShaderSource = `#version 300 es +precision mediump float; + +uniform sampler2D leavingSlideTexture; +uniform sampler2D enteringSlideTexture; +uniform float time; +uniform int effectType; // 0: Fade through black, 1: Fade through white, 2: Smooth fade + +in vec2 v_texCoord; +out vec4 outColor; + +void main() { + vec4 color0 = texture(leavingSlideTexture, v_texCoord); + vec4 color1 = texture(enteringSlideTexture, v_texCoord); + vec4 transitionColor; + + if (effectType == 0) { + // Fade through black + transitionColor = vec4(0.0, 0.0, 0.0, 1.0); + } else if (effectType == 1) { + // Fade through white + transitionColor = vec4(1.0, 1.0, 1.0, 1.0); + } + + if (effectType == 2) { + // Smooth fade + float smoothTime = smoothstep(0.0, 1.0, time); + outColor = mix(color0, color1, smoothTime); + } else { + if (time < 0.5) { + outColor = mix(color0, transitionColor, time * 2.0); + } else { + outColor = mix(transitionColor, color1, (time - 0.5) * 2.0); + } + } +}`; + + const image1 = new Image(); + const image2 = new Image(); + console.log("I'm in fade function"); + + image1.src = 'images/columnline_52x60.svg'; + image2.src = 'images/columnline_52x60.svg'; + + return new FadeTransition( + canvas, + vertexShaderSource, + fragmentShaderSource, + image1, + image2, + ); +}; diff --git a/browser/src/slideshow/transition/Transition2d.ts b/browser/src/slideshow/transition/Transition2d.ts new file mode 100644 index 0000000000..c1027d8c60 --- /dev/null +++ b/browser/src/slideshow/transition/Transition2d.ts @@ -0,0 +1,225 @@ +/* + * Copyright the Collabora Online contributors. + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +class Transition2d { + public canvas: HTMLCanvasElement; + public gl: WebGL2RenderingContext; + public program: WebGLProgram; + public animationTime: number = 1500; + private vao!: WebGLVertexArrayObject | null; + private textures: WebGLTexture[]; + private time: number; + private startTime: number | null; + + constructor( + canvas: HTMLCanvasElement, + vertexShaderSource: string, + fragmentShaderSource: string, + image1: HTMLImageElement, + image2: HTMLImageElement, + ) { + this.canvas = canvas; + this.gl = this.canvas.getContext('webgl2') as WebGL2RenderingContext; + if (!this.gl) { + console.error('WebGL2 not supported'); + throw new Error('WebGL2 not supported'); + } + + const vertexShader = this.createShader( + this.gl.VERTEX_SHADER, + vertexShaderSource, + ); + const fragmentShader = this.createShader( + this.gl.FRAGMENT_SHADER, + fragmentShaderSource, + ); + this.program = this.createProgram(vertexShader, fragmentShader); + + this.textures = this.loadTextures([image1, image2]); + this.time = 0; + this.startTime = null; + } + + public prepareTransition(): void { + this.initBuffers(); + this.initUniforms(); + } + + public startTransition(): void { + this.startTime = performance.now(); + requestAnimationFrame(this.render.bind(this)); + } + + public initBuffers(): void { + const positions = new Float32Array([ + -1.0, -1.0, 0, 0, 1, 1.0, -1.0, 0, 1, 1, -1.0, 1.0, 0, 0, 0, 1.0, 1.0, 0, + 1, 0, + ]); + + const buffer = this.gl.createBuffer(); + this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer); + this.gl.bufferData(this.gl.ARRAY_BUFFER, positions, this.gl.STATIC_DRAW); + + this.vao = this.gl.createVertexArray(); + this.gl.bindVertexArray(this.vao); + + const positionLocation = this.gl.getAttribLocation( + this.program, + 'a_position', + ); + const texCoordLocation = this.gl.getAttribLocation( + this.program, + 'a_texCoord', + ); + + this.gl.enableVertexAttribArray(positionLocation); + this.gl.vertexAttribPointer( + positionLocation, + 3, + this.gl.FLOAT, + false, + 5 * 4, + 0, + ); + + this.gl.enableVertexAttribArray(texCoordLocation); + this.gl.vertexAttribPointer( + texCoordLocation, + 2, + this.gl.FLOAT, + false, + 5 * 4, + 3 * 4, + ); + } + + public initUniforms(): void { + this.gl.useProgram(this.program); + } + + public render(): void { + if (!this.startTime) this.startTime = performance.now(); + this.time = + (performance.now() - this.startTime) / + (this.animationTime > 0 ? this.animationTime : 1500); + + this.gl.viewport(0, 0, this.canvas.width, this.canvas.height); + this.gl.clearColor(0.0, 0.0, 0.0, 1.0); + this.gl.clear(this.gl.COLOR_BUFFER_BIT); + + this.gl.useProgram(this.program); + this.gl.uniform1f( + this.gl.getUniformLocation(this.program, 'time'), + this.time, + ); + + this.gl.activeTexture(this.gl.TEXTURE0); + this.gl.bindTexture(this.gl.TEXTURE_2D, this.textures[0]); + this.gl.uniform1i( + this.gl.getUniformLocation(this.program, 'leavingSlideTexture'), + 0, + ); + + this.gl.activeTexture(this.gl.TEXTURE1); + this.gl.bindTexture(this.gl.TEXTURE_2D, this.textures[1]); + this.gl.uniform1i( + this.gl.getUniformLocation(this.program, 'enteringSlideTexture'), + 1, + ); + + this.renderUniformValue(); + + this.gl.bindVertexArray(this.vao); + this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4); + + if (this.time < 1) { + requestAnimationFrame(this.render.bind(this)); + } else { + console.log('Transition completed'); + } + } + + // eslint-disable-next-line @typescript-eslint/no-empty-function + public renderUniformValue(): void {} + + private loadTextures(images: HTMLImageElement[]): WebGLTexture[] { + return images.map((image, index) => { + const texture = this.gl.createTexture(); + if (!texture) { + throw new Error('Failed to create texture'); + } + this.gl.bindTexture(this.gl.TEXTURE_2D, texture); + this.gl.texImage2D( + this.gl.TEXTURE_2D, + 0, + this.gl.RGBA, + this.gl.RGBA, + this.gl.UNSIGNED_BYTE, + image, + ); + this.gl.texParameteri( + this.gl.TEXTURE_2D, + this.gl.TEXTURE_MIN_FILTER, + this.gl.LINEAR, + ); + this.gl.texParameteri( + this.gl.TEXTURE_2D, + this.gl.TEXTURE_WRAP_S, + this.gl.CLAMP_TO_EDGE, + ); + this.gl.texParameteri( + this.gl.TEXTURE_2D, + this.gl.TEXTURE_WRAP_T, + this.gl.CLAMP_TO_EDGE, + ); + console.log(`Texture ${index + 1} loaded:`, image.src); + return texture; + }); + } + + public createShader(type: number, source: string): WebGLShader { + const shader = this.gl.createShader(type); + if (!shader) { + throw new Error('Failed to create shader'); + } + this.gl.shaderSource(shader, source); + this.gl.compileShader(shader); + if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) { + const info = this.gl.getShaderInfoLog(shader); + this.gl.deleteShader(shader); + throw new Error(`Could not compile shader: ${info}`); + } + console.log( + 'Shader compiled successfully:', + type === this.gl.VERTEX_SHADER ? 'VERTEX' : 'FRAGMENT', + ); + return shader; + } + + public createProgram( + vertexShader: WebGLShader, + fragmentShader: WebGLShader, + ): WebGLProgram { + const program = this.gl.createProgram(); + if (!program) { + throw new Error('Failed to create program'); + } + this.gl.attachShader(program, vertexShader); + this.gl.attachShader(program, fragmentShader); + this.gl.linkProgram(program); + if (!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)) { + const info = this.gl.getProgramInfoLog(program); + this.gl.deleteProgram(program); + throw new Error(`Could not link program: ${info}`); + } + console.log('Program linked successfully'); + return program; + } +} diff --git a/browser/src/slideshow/transition/shader/2dVertexShader.glsl b/browser/src/slideshow/transition/shader/2dVertexShader.glsl new file mode 100644 index 0000000000..9254aefe3f --- /dev/null +++ b/browser/src/slideshow/transition/shader/2dVertexShader.glsl @@ -0,0 +1,9 @@ +#version 300 es +in vec4 a_position; +in vec2 a_texCoord; +out vec2 v_texCoord; + +void main() { + gl_Position = a_position; + v_texCoord = a_texCoord; +} diff --git a/browser/src/slideshow/transition/shader/fadeFragmentShader.glsl b/browser/src/slideshow/transition/shader/fadeFragmentShader.glsl new file mode 100644 index 0000000000..1e5e47ae49 --- /dev/null +++ b/browser/src/slideshow/transition/shader/fadeFragmentShader.glsl @@ -0,0 +1,36 @@ +#version 300 es +precision mediump float; + +uniform sampler2D leavingSlideTexture; +uniform sampler2D enteringSlideTexture; +uniform float time; +uniform int effectType; // 0: Fade through black, 1: Fade through white, 2: Smooth fade + +in vec2 v_texCoord; +out vec4 outColor; + +void main() { + vec4 color0 = texture(leavingSlideTexture, v_texCoord); + vec4 color1 = texture(enteringSlideTexture, v_texCoord); + vec4 transitionColor; + + if (effectType == 0) { + // Fade through black + transitionColor = vec4(0.0, 0.0, 0.0, 1.0); + } else if (effectType == 1) { + // Fade through white + transitionColor = vec4(1.0, 1.0, 1.0, 1.0); + } + + if (effectType == 2) { + // Smooth fade + float smoothTime = smoothstep(0.0, 1.0, time); + outColor = mix(color0, color1, smoothTime); + } else { + if (time < 0.5) { + outColor = mix(color0, transitionColor, time * 2.0); + } else { + outColor = mix(transitionColor, color1, (time - 0.5) * 2.0); + } + } +} |