package.src.render.program.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mapbox-gl Show documentation
Show all versions of mapbox-gl Show documentation
A WebGL interactive maps library
The newest version!
// @flow
import {prelude} from '../shaders';
import assert from 'assert';
import ProgramConfiguration from '../data/program_configuration';
import VertexArrayObject from './vertex_array_object';
import Context from '../gl/context';
import type SegmentVector from '../data/segment';
import type VertexBuffer from '../gl/vertex_buffer';
import type IndexBuffer from '../gl/index_buffer';
import type DepthMode from '../gl/depth_mode';
import type StencilMode from '../gl/stencil_mode';
import type ColorMode from '../gl/color_mode';
import type CullFaceMode from '../gl/cull_face_mode';
import type {UniformBindings, UniformValues, UniformLocations} from './uniform_binding';
import type {BinderUniform} from '../data/program_configuration';
export type DrawMode =
| $PropertyType
| $PropertyType
| $PropertyType;
function getTokenizedAttributesAndUniforms (array: Array): Array {
const result = [];
for (let i = 0; i < array.length; i++) {
if (array[i] === null) continue;
const token = array[i].split(' ');
result.push(token.pop());
}
return result;
}
class Program {
program: WebGLProgram;
attributes: {[_: string]: number};
numAttributes: number;
fixedUniforms: Us;
binderUniforms: Array;
failedToCreate: boolean;
constructor(context: Context,
name: string,
source: {fragmentSource: string, vertexSource: string, staticAttributes: Array, staticUniforms: Array},
configuration: ?ProgramConfiguration,
fixedUniforms: (Context, UniformLocations) => Us,
showOverdrawInspector: boolean) {
const gl = context.gl;
this.program = gl.createProgram();
const staticAttrInfo = getTokenizedAttributesAndUniforms(source.staticAttributes);
const dynamicAttrInfo = configuration ? configuration.getBinderAttributes() : [];
const allAttrInfo = staticAttrInfo.concat(dynamicAttrInfo);
const staticUniformsInfo = source.staticUniforms ? getTokenizedAttributesAndUniforms(source.staticUniforms) : [];
const dynamicUniformsInfo = configuration ? configuration.getBinderUniforms() : [];
// remove duplicate uniforms
const uniformList = staticUniformsInfo.concat(dynamicUniformsInfo);
const allUniformsInfo = [];
for (const uniform of uniformList) {
if (allUniformsInfo.indexOf(uniform) < 0) allUniformsInfo.push(uniform);
}
const defines = configuration ? configuration.defines() : [];
if (showOverdrawInspector) {
defines.push('#define OVERDRAW_INSPECTOR;');
}
const fragmentSource = defines.concat(prelude.fragmentSource, source.fragmentSource).join('\n');
const vertexSource = defines.concat(prelude.vertexSource, source.vertexSource).join('\n');
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
if (gl.isContextLost()) {
this.failedToCreate = true;
return;
}
gl.shaderSource(fragmentShader, fragmentSource);
gl.compileShader(fragmentShader);
assert(gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS), (gl.getShaderInfoLog(fragmentShader): any));
gl.attachShader(this.program, fragmentShader);
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
if (gl.isContextLost()) {
this.failedToCreate = true;
return;
}
gl.shaderSource(vertexShader, vertexSource);
gl.compileShader(vertexShader);
assert(gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS), (gl.getShaderInfoLog(vertexShader): any));
gl.attachShader(this.program, vertexShader);
this.attributes = {};
const uniformLocations = {};
this.numAttributes = allAttrInfo.length;
for (let i = 0; i < this.numAttributes; i++) {
if (allAttrInfo[i]) {
gl.bindAttribLocation(this.program, i, allAttrInfo[i]);
this.attributes[allAttrInfo[i]] = i;
}
}
gl.linkProgram(this.program);
assert(gl.getProgramParameter(this.program, gl.LINK_STATUS), (gl.getProgramInfoLog(this.program): any));
gl.deleteShader(vertexShader);
gl.deleteShader(fragmentShader);
for (let it = 0; it < allUniformsInfo.length; it++) {
const uniform = allUniformsInfo[it];
if (uniform && !uniformLocations[uniform]) {
const uniformLocation = gl.getUniformLocation(this.program, uniform);
if (uniformLocation) {
uniformLocations[uniform] = uniformLocation;
}
}
}
this.fixedUniforms = fixedUniforms(context, uniformLocations);
this.binderUniforms = configuration ? configuration.getUniforms(context, uniformLocations) : [];
}
draw(context: Context,
drawMode: DrawMode,
depthMode: $ReadOnly,
stencilMode: $ReadOnly,
colorMode: $ReadOnly,
cullFaceMode: $ReadOnly,
uniformValues: UniformValues,
layerID: string,
layoutVertexBuffer: VertexBuffer,
indexBuffer: IndexBuffer,
segments: SegmentVector,
currentProperties: any,
zoom: ?number,
configuration: ?ProgramConfiguration,
dynamicLayoutBuffer: ?VertexBuffer,
dynamicLayoutBuffer2: ?VertexBuffer) {
const gl = context.gl;
if (this.failedToCreate) return;
context.program.set(this.program);
context.setDepthMode(depthMode);
context.setStencilMode(stencilMode);
context.setColorMode(colorMode);
context.setCullFace(cullFaceMode);
for (const name in this.fixedUniforms) {
this.fixedUniforms[name].set(uniformValues[name]);
}
if (configuration) {
configuration.setUniforms(context, this.binderUniforms, currentProperties, {zoom: (zoom: any)});
}
const primitiveSize = {
[gl.LINES]: 2,
[gl.TRIANGLES]: 3,
[gl.LINE_STRIP]: 1
}[drawMode];
for (const segment of segments.get()) {
const vaos = segment.vaos || (segment.vaos = {});
const vao: VertexArrayObject = vaos[layerID] || (vaos[layerID] = new VertexArrayObject());
vao.bind(
context,
this,
layoutVertexBuffer,
configuration ? configuration.getPaintVertexBuffers() : [],
indexBuffer,
segment.vertexOffset,
dynamicLayoutBuffer,
dynamicLayoutBuffer2
);
gl.drawElements(
drawMode,
segment.primitiveLength * primitiveSize,
gl.UNSIGNED_SHORT,
segment.primitiveOffset * primitiveSize * 2);
}
}
}
export default Program;