Webgl shader builder / expanded functionality

Now takes in a custom object with attributes, uniforms etc.
The WebGLPointsLayer uses this to handle image icons.
This commit is contained in:
Olivier Guyot
2019-09-25 14:49:14 +02:00
parent b8564d503a
commit 34572da17b
3 changed files with 258 additions and 148 deletions
+43 -3
View File
@@ -4,8 +4,15 @@
import VectorLayer from './Vector.js'; import VectorLayer from './Vector.js';
import {assign} from '../obj.js'; import {assign} from '../obj.js';
import WebGLPointsLayerRenderer from '../renderer/webgl/PointsLayer.js'; import WebGLPointsLayerRenderer from '../renderer/webgl/PointsLayer.js';
import {getSymbolFragmentShader, getSymbolVertexShader} from '../webgl/ShaderBuilder.js'; import {
formatArray,
formatColor,
formatNumber,
getSymbolFragmentShader,
getSymbolVertexShader
} from '../webgl/ShaderBuilder.js';
import {assert} from '../asserts.js'; import {assert} from '../asserts.js';
import {asArray} from '../color.js';
/** /**
@@ -59,9 +66,42 @@ class WebGLPointsLayer extends VectorLayer {
* @inheritDoc * @inheritDoc
*/ */
createRenderer() { createRenderer() {
const symbolStyle = this.literalStyle.symbol;
const size = Array.isArray(symbolStyle.size) ?
formatArray(symbolStyle.size) : formatNumber(symbolStyle.size);
const color = symbolStyle.color !== undefined ?
(typeof symbolStyle.color === 'string' ? asArray(symbolStyle.color) : symbolStyle.color) :
[255, 255, 255, 1];
const texCoord = symbolStyle.textureCoord || [0, 0, 1, 1];
const offset = symbolStyle.offset || [0, 0];
const opacity = symbolStyle.opacity !== undefined ? symbolStyle.opacity : 1;
/** @type {import('../webgl/ShaderBuilder.js').ShaderParameters} */
const params = {
uniforms: [],
colorExpression: 'vec4(' + formatColor(color) + ') * vec4(1.0, 1.0, 1.0, ' + formatNumber(opacity) + ')',
sizeExpression: 'vec2(' + size + ')',
offsetExpression: 'vec2(' + formatArray(offset) + ')',
texCoordExpression: 'vec4(' + formatArray(texCoord) + ')',
rotateWithView: !!symbolStyle.rotateWithView
};
/** @type {Object.<string,import("../webgl/Helper").UniformValue>} */
const uniforms = {};
if (symbolStyle.symbolType === 'image' && symbolStyle.src) {
const texture = new Image();
texture.src = symbolStyle.src;
params.uniforms.push('sampler2D u_texture');
params.colorExpression = params.colorExpression +
' * texture2D(u_texture, v_texCoord);';
uniforms['u_texture'] = texture;
}
return new WebGLPointsLayerRenderer(this, { return new WebGLPointsLayerRenderer(this, {
vertexShader: getSymbolVertexShader(this.literalStyle.symbol), vertexShader: getSymbolVertexShader(params),
fragmentShader: getSymbolFragmentShader() fragmentShader: getSymbolFragmentShader(params),
uniforms: uniforms
}); });
} }
} }
+74 -42
View File
@@ -1,5 +1,3 @@
import {asArray} from '../color.js';
/** /**
* Utilities for generating shaders from literal style objects * Utilities for generating shaders from literal style objects
* @module ol/webgl/ShaderBuilder * @module ol/webgl/ShaderBuilder
@@ -15,6 +13,15 @@ export function formatNumber(v) {
return s.indexOf('.') === -1 ? s + '.0' : s; return s.indexOf('.') === -1 ? s + '.0' : s;
} }
/**
* Will return the number array as a float with a dot separator, concatenated with ', '.
* @param {Array<number>} array Numerical values array.
* @returns {string} The array as string, e. g.: `1.0, 2.0, 3.0`.
*/
export function formatArray(array) {
return array.map(formatNumber).join(', ');
}
/** /**
* Will normalize and converts to string a color array compatible with GLSL. * Will normalize and converts to string a color array compatible with GLSL.
* @param {Array<number>} colorArray Color in [r, g, b, a] array form, with RGB components in the * @param {Array<number>} colorArray Color in [r, g, b, a] array form, with RGB components in the
@@ -29,54 +36,78 @@ export function formatColor(colorArray) {
} }
/** /**
* Generates a symbol vertex shader from a literal style, * @typedef {Object} VaryingDescription
* @property {string} name Varying name, as will be declared in the header.
* @property {string} type Varying type, either `float`, `vec2`, `vec4`...
* @property {string} expression Expression which will be assigned to the varying in the vertex shader, and
* passed on to the fragment shader.
*/
/**
* @typedef {Object} ShaderParameters
* @property {Array<string>} [uniforms] Uniforms; these will be declared in the header (should include the type).
* @property {Array<string>} [attributes] Attributes; these will be declared in the header (should include the type).
* @property {Array<VaryingDescription>} [varyings] Varyings with a name, a type and an expression.
* @property {string} sizeExpression This will be assigned to a `vec2 size` variable.
* @property {string} offsetExpression This will be assigned to a `vec2 offset` variable.
* @property {string} colorExpression This will be the value assigned to gl_FragColor
* @property {string} texCoordExpression This will be the value assigned to the `vec4 v_texCoord` varying.
* @property {boolean} [rotateWithView=false] Whether symbols should rotate with view
*/
/**
* Generates a symbol vertex shader from a set of parameters,
* intended to be used on point geometries. * intended to be used on point geometries.
* *
* Expected the following attributes to be present in the attribute array: * Three uniforms are hardcoded in all shaders: `u_projectionMatrix`, `u_offsetScaleMatrix` and
* `u_offsetRotateMatrix`.
*
* The following attributes are hardcoded and expected to be present in the vertex buffers:
* `vec2 a_position`, `float a_index` (being the index of the vertex in the quad, 0 to 3). * `vec2 a_position`, `float a_index` (being the index of the vertex in the quad, 0 to 3).
* *
* Transmits the following varyings to the fragment shader: * @param {ShaderParameters} parameters Parameters for the shader.
* `vec2 v_texCoord`, `float v_opacity`, `vec4 v_color`
*
* @param {import('../style/LiteralStyle.js').LiteralSymbolStyle} parameters Parameters for the shader.
* @returns {string} The full shader as a string. * @returns {string} The full shader as a string.
*/ */
export function getSymbolVertexShader(parameters) { export function getSymbolVertexShader(parameters) {
const offsetMatrix = parameters.rotateWithView ? const offsetMatrix = parameters.rotateWithView ?
'mat4 offsetMatrix = u_offsetScaleMatrix * u_offsetRotateMatrix;' : 'u_offsetScaleMatrix * u_offsetRotateMatrix' :
'mat4 offsetMatrix = u_offsetScaleMatrix;'; 'u_offsetScaleMatrix';
const offset = parameters.offset || [0, 0]; const uniforms = parameters.uniforms || [];
const size = Array.isArray(parameters.size) ? parameters.size : [parameters.size, parameters.size]; const attributes = parameters.attributes || [];
const texCoord = parameters.textureCoord || [0, 0, 1, 1]; const varyings = parameters.varyings || [];
const opacity = parameters.opacity !== undefined ? parameters.opacity : 1;
const color = parameters.color !== undefined ?
(typeof parameters.color === 'string' ? asArray(parameters.color) : parameters.color) :
[255, 255, 255, 1];
const f = formatNumber;
const body = `precision mediump float; const body = `precision mediump float;
uniform mat4 u_projectionMatrix; uniform mat4 u_projectionMatrix;
uniform mat4 u_offsetScaleMatrix; uniform mat4 u_offsetScaleMatrix;
uniform mat4 u_offsetRotateMatrix; uniform mat4 u_offsetRotateMatrix;
${uniforms.map(function(uniform) {
return 'uniform ' + uniform + ';';
}).join('\n')}
attribute vec2 a_position; attribute vec2 a_position;
attribute float a_index; attribute float a_index;
${attributes.map(function(attribute) {
return 'attribute ' + attribute + ';';
}).join('\n')}
varying vec2 v_texCoord; varying vec2 v_texCoord;
varying float v_opacity; ${varyings.map(function(varying) {
varying vec4 v_color; return 'varying ' + varying.type + ' ' + varying.name + ';';
}).join('\n')}
void main(void) { void main(void) {
${offsetMatrix} mat4 offsetMatrix = ${offsetMatrix};
float offsetX = a_index == 0.0 || a_index == 3.0 ? ${f(offset[0] - size[0] / 2)} : ${f(offset[0] + size[0] / 2)}; vec2 size = ${parameters.sizeExpression};
float offsetY = a_index == 0.0 || a_index == 1.0 ? ${f(offset[1] - size[1] / 2)} : ${f(offset[1] + size[1] / 2)}; vec2 offset = ${parameters.offsetExpression};
float offsetX = a_index == 0.0 || a_index == 3.0 ? offset.x - size.x / 2.0 : offset.x + size.x / 2.0;
float offsetY = a_index == 0.0 || a_index == 1.0 ? offset.y - size.y / 2.0 : offset.y + size.y / 2.0;
vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0); vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0);
gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets; gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;
float u = a_index == 0.0 || a_index == 3.0 ? ${f(texCoord[0])} : ${f(texCoord[2])}; vec4 texCoord = ${parameters.texCoordExpression};
float v = a_index == 0.0 || a_index == 1.0 ? ${f(texCoord[1])} : ${f(texCoord[3])}; float u = a_index == 0.0 || a_index == 3.0 ? texCoord.s : texCoord.q;
float v = a_index == 2.0 || a_index == 3.0 ? texCoord.t : texCoord.p;
v_texCoord = vec2(u, v); v_texCoord = vec2(u, v);
v_opacity = ${f(opacity)}; ${varyings.map(function(varying) {
v_color = vec4(${formatColor(color)}); return ' ' + varying.name + ' = ' + varying.expression + ';';
}).join('\n')}
}`; }`;
return body; return body;
@@ -86,24 +117,25 @@ void main(void) {
* Generates a symbol fragment shader intended to be used on point geometries. * Generates a symbol fragment shader intended to be used on point geometries.
* *
* Expected the following varyings to be transmitted by the vertex shader: * Expected the following varyings to be transmitted by the vertex shader:
* `vec2 v_texCoord`, `float v_opacity`, `vec4 v_color` * `vec2 v_texCoord`
* *
* @param {ShaderParameters} parameters Parameters for the shader.
* @returns {string} The full shader as a string. * @returns {string} The full shader as a string.
*/ */
export function getSymbolFragmentShader() { export function getSymbolFragmentShader(parameters) {
const body = `precision mediump float; const uniforms = parameters.uniforms || [];
uniform sampler2D u_texture; const varyings = parameters.varyings || [];
varying vec2 v_texCoord;
varying float v_opacity;
varying vec4 v_color;
const body = `precision mediump float;
${uniforms.map(function(uniform) {
return 'uniform ' + uniform + ';';
}).join('\n')}
varying vec2 v_texCoord;
${varyings.map(function(varying) {
return 'varying ' + varying.type + ' ' + varying.name + ';';
}).join('\n')}
void main(void) { void main(void) {
if (v_opacity == 0.0) { gl_FragColor = ${parameters.colorExpression};
discard;
}
vec4 textureColor = texture2D(u_texture, v_texCoord);
gl_FragColor = v_color * textureColor;
gl_FragColor.a *= v_opacity;
gl_FragColor.rgb *= gl_FragColor.a; gl_FragColor.rgb *= gl_FragColor.a;
}`; }`;
+141 -103
View File
@@ -1,4 +1,9 @@
import {getSymbolVertexShader, formatNumber, getSymbolFragmentShader} from '../../../../src/ol/webgl/ShaderBuilder.js'; import {
getSymbolVertexShader,
formatNumber,
getSymbolFragmentShader,
formatColor, formatArray
} from '../../../../src/ol/webgl/ShaderBuilder.js';
describe('ol.webgl.ShaderBuilder', function() { describe('ol.webgl.ShaderBuilder', function() {
@@ -12,147 +17,180 @@ describe('ol.webgl.ShaderBuilder', function() {
}); });
}); });
describe('formatArray', function() {
it('outputs numbers with dot separators', function() {
expect(formatArray([1, 0, 3.45, 0.8888])).to.eql('1.0, 0.0, 3.45, 0.8888');
});
});
describe('formatColor', function() {
it('normalizes color and outputs numbers with dot separators', function() {
expect(formatColor([100, 0, 255, 1])).to.eql('0.39215686274509803, 0.0, 1.0, 1.0');
});
});
describe('getSymbolVertexShader', function() { describe('getSymbolVertexShader', function() {
it('generates a symbol vertex shader without using additional attributes', function() { it('generates a symbol vertex shader (with varying)', function() {
expect(getSymbolVertexShader( const parameters = {
{ varyings: [{
rotateWithView: false, name: 'v_opacity',
color: '#5000ff', type: 'float',
opacity: 0.4, expression: formatNumber(0.4)
offset: [5, -7], }, {
size: 6, name: 'v_test',
textureCoord: [0, 0.5, 0.5, 1] type: 'vec3',
})).to.eql(`precision mediump float; expression: 'vec3(' + formatArray([1, 2, 3]) + ')'
}],
sizeExpression: 'vec2(' + formatNumber(6) + ')',
offsetExpression: 'vec2(' + formatArray([5, -7]) + ')',
colorExpression: 'vec4(' + formatColor([80, 0, 255, 1]) + ')',
texCoordExpression: 'vec4(' + formatArray([0, 0.5, 0.5, 1]) + ')',
rotateWithView: false
};
expect(getSymbolVertexShader(parameters)).to.eql(`precision mediump float;
uniform mat4 u_projectionMatrix; uniform mat4 u_projectionMatrix;
uniform mat4 u_offsetScaleMatrix; uniform mat4 u_offsetScaleMatrix;
uniform mat4 u_offsetRotateMatrix; uniform mat4 u_offsetRotateMatrix;
attribute vec2 a_position; attribute vec2 a_position;
attribute float a_index; attribute float a_index;
varying vec2 v_texCoord; varying vec2 v_texCoord;
varying float v_opacity; varying float v_opacity;
varying vec4 v_color; varying vec3 v_test;
void main(void) {
mat4 offsetMatrix = u_offsetScaleMatrix;
vec2 size = vec2(6.0);
vec2 offset = vec2(5.0, -7.0);
float offsetX = a_index == 0.0 || a_index == 3.0 ? offset.x - size.x / 2.0 : offset.x + size.x / 2.0;
float offsetY = a_index == 0.0 || a_index == 1.0 ? offset.y - size.y / 2.0 : offset.y + size.y / 2.0;
vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0);
gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;
vec4 texCoord = vec4(0.0, 0.5, 0.5, 1.0);
float u = a_index == 0.0 || a_index == 3.0 ? texCoord.s : texCoord.q;
float v = a_index == 2.0 || a_index == 3.0 ? texCoord.t : texCoord.p;
v_texCoord = vec2(u, v);
v_opacity = 0.4;
v_test = vec3(1.0, 2.0, 3.0);
}`);
});
it('generates a symbol vertex shader (with uniforms and attributes)', function() {
const parameters = {
uniforms: ['float u_myUniform'],
attributes: ['vec2 a_myAttr'],
sizeExpression: 'vec2(' + formatNumber(6) + ')',
offsetExpression: 'vec2(' + formatArray([5, -7]) + ')',
colorExpression: 'vec4(' + formatColor([80, 0, 255, 1]) + ')',
texCoordExpression: 'vec4(' + formatArray([0, 0.5, 0.5, 1]) + ')'
};
expect(getSymbolVertexShader(parameters)).to.eql(`precision mediump float;
uniform mat4 u_projectionMatrix;
uniform mat4 u_offsetScaleMatrix;
uniform mat4 u_offsetRotateMatrix;
uniform float u_myUniform;
attribute vec2 a_position;
attribute float a_index;
attribute vec2 a_myAttr;
varying vec2 v_texCoord;
void main(void) { void main(void) {
mat4 offsetMatrix = u_offsetScaleMatrix; mat4 offsetMatrix = u_offsetScaleMatrix;
float offsetX = a_index == 0.0 || a_index == 3.0 ? 2.0 : 8.0; vec2 size = vec2(6.0);
float offsetY = a_index == 0.0 || a_index == 1.0 ? -10.0 : -4.0; vec2 offset = vec2(5.0, -7.0);
float offsetX = a_index == 0.0 || a_index == 3.0 ? offset.x - size.x / 2.0 : offset.x + size.x / 2.0;
float offsetY = a_index == 0.0 || a_index == 1.0 ? offset.y - size.y / 2.0 : offset.y + size.y / 2.0;
vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0); vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0);
gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets; gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;
float u = a_index == 0.0 || a_index == 3.0 ? 0.0 : 0.5; vec4 texCoord = vec4(0.0, 0.5, 0.5, 1.0);
float v = a_index == 0.0 || a_index == 1.0 ? 0.5 : 1.0; float u = a_index == 0.0 || a_index == 3.0 ? texCoord.s : texCoord.q;
float v = a_index == 2.0 || a_index == 3.0 ? texCoord.t : texCoord.p;
v_texCoord = vec2(u, v); v_texCoord = vec2(u, v);
v_opacity = 0.4;
v_color = vec4(0.3137254901960784, 0.0, 1.0, 1.0);
}`);
});
it('correctly handles size as an array', function() {
expect(getSymbolVertexShader(
{
rotateWithView: false,
color: '#5000ff',
opacity: 0.4,
offset: [5, -7],
size: [10, 12],
textureCoord: [0, 0.5, 0.5, 1]
})).to.eql(`precision mediump float;
uniform mat4 u_projectionMatrix;
uniform mat4 u_offsetScaleMatrix;
uniform mat4 u_offsetRotateMatrix;
attribute vec2 a_position;
attribute float a_index;
varying vec2 v_texCoord;
varying float v_opacity;
varying vec4 v_color;
void main(void) {
mat4 offsetMatrix = u_offsetScaleMatrix;
float offsetX = a_index == 0.0 || a_index == 3.0 ? 0.0 : 10.0;
float offsetY = a_index == 0.0 || a_index == 1.0 ? -13.0 : -1.0;
vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0);
gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;
float u = a_index == 0.0 || a_index == 3.0 ? 0.0 : 0.5;
float v = a_index == 0.0 || a_index == 1.0 ? 0.5 : 1.0;
v_texCoord = vec2(u, v);
v_opacity = 0.4;
v_color = vec4(0.3137254901960784, 0.0, 1.0, 1.0);
}`); }`);
}); });
it('correctly handles rotate with view', function() { it('generates a symbol vertex shader (with rotateWithView)', function() {
expect(getSymbolVertexShader( const parameters = {
{ sizeExpression: 'vec2(' + formatNumber(6) + ')',
rotateWithView: true, offsetExpression: 'vec2(' + formatArray([5, -7]) + ')',
color: '#5000ff', colorExpression: 'vec4(' + formatColor([80, 0, 255, 1]) + ')',
opacity: 0.4, texCoordExpression: 'vec4(' + formatArray([0, 0.5, 0.5, 1]) + ')',
size: 6, rotateWithView: true
textureCoord: [0, 0.5, 0.5, 1] };
})).to.eql(`precision mediump float;
expect(getSymbolVertexShader(parameters)).to.eql(`precision mediump float;
uniform mat4 u_projectionMatrix; uniform mat4 u_projectionMatrix;
uniform mat4 u_offsetScaleMatrix; uniform mat4 u_offsetScaleMatrix;
uniform mat4 u_offsetRotateMatrix; uniform mat4 u_offsetRotateMatrix;
attribute vec2 a_position; attribute vec2 a_position;
attribute float a_index; attribute float a_index;
varying vec2 v_texCoord; varying vec2 v_texCoord;
varying float v_opacity;
varying vec4 v_color;
void main(void) { void main(void) {
mat4 offsetMatrix = u_offsetScaleMatrix * u_offsetRotateMatrix; mat4 offsetMatrix = u_offsetScaleMatrix * u_offsetRotateMatrix;
float offsetX = a_index == 0.0 || a_index == 3.0 ? -3.0 : 3.0; vec2 size = vec2(6.0);
float offsetY = a_index == 0.0 || a_index == 1.0 ? -3.0 : 3.0; vec2 offset = vec2(5.0, -7.0);
float offsetX = a_index == 0.0 || a_index == 3.0 ? offset.x - size.x / 2.0 : offset.x + size.x / 2.0;
float offsetY = a_index == 0.0 || a_index == 1.0 ? offset.y - size.y / 2.0 : offset.y + size.y / 2.0;
vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0); vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0);
gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets; gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;
float u = a_index == 0.0 || a_index == 3.0 ? 0.0 : 0.5; vec4 texCoord = vec4(0.0, 0.5, 0.5, 1.0);
float v = a_index == 0.0 || a_index == 1.0 ? 0.5 : 1.0; float u = a_index == 0.0 || a_index == 3.0 ? texCoord.s : texCoord.q;
float v = a_index == 2.0 || a_index == 3.0 ? texCoord.t : texCoord.p;
v_texCoord = vec2(u, v); v_texCoord = vec2(u, v);
v_opacity = 0.4;
v_color = vec4(0.3137254901960784, 0.0, 1.0, 1.0);
}`);
});
it('correctly handles missing optional parameters', function() {
expect(getSymbolVertexShader(
{
rotateWithView: false,
size: 5
})).to.eql(`precision mediump float;
uniform mat4 u_projectionMatrix;
uniform mat4 u_offsetScaleMatrix;
uniform mat4 u_offsetRotateMatrix;
attribute vec2 a_position;
attribute float a_index;
varying vec2 v_texCoord;
varying float v_opacity;
varying vec4 v_color;
void main(void) {
mat4 offsetMatrix = u_offsetScaleMatrix;
float offsetX = a_index == 0.0 || a_index == 3.0 ? -2.5 : 2.5;
float offsetY = a_index == 0.0 || a_index == 1.0 ? -2.5 : 2.5;
vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0);
gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;
float u = a_index == 0.0 || a_index == 3.0 ? 0.0 : 1.0;
float v = a_index == 0.0 || a_index == 1.0 ? 0.0 : 1.0;
v_texCoord = vec2(u, v);
v_opacity = 1.0;
v_color = vec4(1.0, 1.0, 1.0, 1.0);
}`); }`);
}); });
}); });
describe('getSymbolFragmentShader', function() { describe('getSymbolFragmentShader', function() {
it('generates a fixed shader', function() { it('generates a symbol fragment shader (with varying)', function() {
expect(getSymbolFragmentShader()).to.eql(`precision mediump float; const parameters = {
uniform sampler2D u_texture; varyings: [{
name: 'v_opacity',
type: 'float',
expression: formatNumber(0.4)
}, {
name: 'v_test',
type: 'vec3',
expression: 'vec3(' + formatArray([1, 2, 3]) + ')'
}],
sizeExpression: 'vec2(' + formatNumber(6) + ')',
offsetExpression: 'vec2(' + formatArray([5, -7]) + ')',
colorExpression: 'vec4(' + formatColor([80, 0, 255]) + ', v_opacity)',
texCoordExpression: 'vec4(' + formatArray([0, 0.5, 0.5, 1]) + ')',
rotateWithView: false
};
expect(getSymbolFragmentShader(parameters)).to.eql(`precision mediump float;
varying vec2 v_texCoord; varying vec2 v_texCoord;
varying float v_opacity; varying float v_opacity;
varying vec4 v_color; varying vec3 v_test;
void main(void) {
gl_FragColor = vec4(0.3137254901960784, 0.0, 1.0, v_opacity);
gl_FragColor.rgb *= gl_FragColor.a;
}`);
});
it('generates a symbol fragment shader (with uniforms)', function() {
const parameters = {
uniforms: ['float u_myUniform', 'vec2 u_myUniform2'],
sizeExpression: 'vec2(' + formatNumber(6) + ')',
offsetExpression: 'vec2(' + formatArray([5, -7]) + ')',
colorExpression: 'vec4(' + formatColor([255, 255, 255, 1]) + ')',
texCoordExpression: 'vec4(' + formatArray([0, 0.5, 0.5, 1]) + ')'
};
expect(getSymbolFragmentShader(parameters)).to.eql(`precision mediump float;
uniform float u_myUniform;
uniform vec2 u_myUniform2;
varying vec2 v_texCoord;
void main(void) { void main(void) {
if (v_opacity == 0.0) { gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
discard;
}
vec4 textureColor = texture2D(u_texture, v_texCoord);
gl_FragColor = v_color * textureColor;
gl_FragColor.a *= v_opacity;
gl_FragColor.rgb *= gl_FragColor.a; gl_FragColor.rgb *= gl_FragColor.a;
}`); }`);
}); });