Source: ShaderCombiner.js

import { Shader } from './Shader.js'

/**
 * @typedef {Object} ShaderCombiner~Operation
 * A shader operation that combines two textures.
 * @property {string} first - Assigns first texture as output (cout = c1)
 * @property {string} second - Assigns second texture as output (cout = c2)
 * @property {string} mean - Calculates average of textures (cout = (c1 + c2)/2.0)
 * @property {string} diff - Calculates difference between textures (cout = c2.rgb - c1.rgb)
 */

/**
 * Fired when shader combination mode changes.
 * @event ShaderCombiner#update
 * @type {Object}
 * @property {string} mode - New combination mode
 * @property {string} previousMode - Previous combination mode
 */

/**
 * ShaderCombiner module provides texture combination operations for OpenLIME.
 * Supports both WebGL 1.0 and 2.0/3.0 GLSL specifications with automatic version detection.
 * 
 * ShaderCombiner class manages the combination of two input textures using various operations.
 * Features:
 * - Multiple combination modes (first, second, mean, diff)
 * - Automatic texture sampling
 * - WebGL 1.0 and 2.0 compatibility
 * - Alpha channel preservation
 * 
 * @extends Shader
 */
class ShaderCombiner extends Shader {
	/**
	 * Creates a new ShaderCombiner instance.
	 * @param {Object} [options] - Configuration options
	 * @param {string} [options.mode='mean'] - Combination mode to use
	 * @param {Array<Object>} [options.samplers] - Texture sampler definitions (inherited from Shader)
	 * @param {Object} [options.uniforms] - Shader uniform variables (inherited from Shader)
	 * @param {string} [options.label] - Display label for the shader (inherited from Shader)
	 * @param {boolean} [options.debug] - Enable debug output (inherited from Shader)
	 * @fires Shader#update
	 */
	constructor(options) {
		super(options);

		this.mode = 'mean', //Lighten Darken Contrast Inversion HSV components LCh components
			this.samplers = [
				{ id: 0, name: 'source1', type: 'vec3' },
				{ id: 1, name: 'source2', type: 'vec3' }
			];

		this.modes = ['first', 'second', 'mean', 'diff'];
		this.operations = {
			'first': 'color = c1;',
			'second': 'color = c2;',
			'mean': 'color = (c1 + c2)/2.0;',
			'diff': 'color = vec4(c2.rgb - c1.rgb, c1.a);'
		};
	}

	/**
	 * Gets fragment shader source code.
	 * Implements texture combination operations.
	 * @param {WebGLRenderingContext} gl - WebGL context
	 * @returns {string} Fragment shader source code
	 * @private
	 */
	fragShaderSrc(gl) {
		let gl2 = !(gl instanceof WebGLRenderingContext);
		let operation = this.operations[this.mode];
		return `

${gl2 ? 'in' : 'varying'} vec2 v_texcoord;

uniform sampler2D source1;
uniform sampler2D source2;

vec4 data() {
	vec4 c1 = texture(source1, v_texcoord);
	vec4 c2 = texture(source2, v_texcoord);
	vec4 color;
	${operation};
	return color;
}
`;
	}

	/**
	 * Gets vertex shader source code.
	 * Provides basic vertex transformation and texture coordinate passing.
	 * @param {WebGLRenderingContext} gl - WebGL context
	 * @returns {string} Vertex shader source code
	 * @private
	 */
	vertShaderSrc(gl) {
		let gl2 = !(gl instanceof WebGLRenderingContext);
		return `${gl2 ? '#version 300 es' : ''}


${gl2 ? 'in' : 'attribute'} vec4 a_position;
${gl2 ? 'in' : 'attribute'} vec2 a_texcoord;

${gl2 ? 'out' : 'varying'} vec2 v_texcoord;

void main() {
	gl_Position = a_position;
	v_texcoord = a_texcoord;
}`;
	}
}

export { ShaderCombiner }