StackGenVis: Alignment of Data, Algorithms, and Models for Stacking Ensemble Learning Using Performance Metrics
https://doi.org/10.1109/TVCG.2020.3030352
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
264 lines
7.0 KiB
264 lines
7.0 KiB
'use strict'
|
|
|
|
var createUniformWrapper = require('./lib/create-uniforms')
|
|
var createAttributeWrapper = require('./lib/create-attributes')
|
|
var makeReflect = require('./lib/reflect')
|
|
var shaderCache = require('./lib/shader-cache')
|
|
var runtime = require('./lib/runtime-reflect')
|
|
var GLError = require("./lib/GLError")
|
|
|
|
//Shader object
|
|
function Shader(gl) {
|
|
this.gl = gl
|
|
this.gl.lastAttribCount = 0 // fixme where else should we store info, safe but not nice on the gl object
|
|
|
|
//Default initialize these to null
|
|
this._vref =
|
|
this._fref =
|
|
this._relink =
|
|
this.vertShader =
|
|
this.fragShader =
|
|
this.program =
|
|
this.attributes =
|
|
this.uniforms =
|
|
this.types = null
|
|
}
|
|
|
|
var proto = Shader.prototype
|
|
|
|
proto.bind = function() {
|
|
if(!this.program) {
|
|
this._relink()
|
|
}
|
|
|
|
// ensuring that we have the right number of enabled vertex attributes
|
|
var i
|
|
var newAttribCount = this.gl.getProgramParameter(this.program, this.gl.ACTIVE_ATTRIBUTES) // more robust approach
|
|
//var newAttribCount = Object.keys(this.attributes).length // avoids the probably immaterial introspection slowdown
|
|
var oldAttribCount = this.gl.lastAttribCount
|
|
if(newAttribCount > oldAttribCount) {
|
|
for(i = oldAttribCount; i < newAttribCount; i++) {
|
|
this.gl.enableVertexAttribArray(i)
|
|
}
|
|
} else if(oldAttribCount > newAttribCount) {
|
|
for(i = newAttribCount; i < oldAttribCount; i++) {
|
|
this.gl.disableVertexAttribArray(i)
|
|
}
|
|
}
|
|
|
|
this.gl.lastAttribCount = newAttribCount
|
|
|
|
this.gl.useProgram(this.program)
|
|
}
|
|
|
|
proto.dispose = function() {
|
|
|
|
// disabling vertex attributes so new shader starts with zero
|
|
// and it's also useful if all shaders are disposed but the
|
|
// gl context is reused for subsequent replotting
|
|
var oldAttribCount = this.gl.lastAttribCount
|
|
for (var i = 0; i < oldAttribCount; i++) {
|
|
this.gl.disableVertexAttribArray(i)
|
|
}
|
|
this.gl.lastAttribCount = 0
|
|
|
|
if(this._fref) {
|
|
this._fref.dispose()
|
|
}
|
|
if(this._vref) {
|
|
this._vref.dispose()
|
|
}
|
|
this.attributes =
|
|
this.types =
|
|
this.vertShader =
|
|
this.fragShader =
|
|
this.program =
|
|
this._relink =
|
|
this._fref =
|
|
this._vref = null
|
|
}
|
|
|
|
function compareAttributes(a, b) {
|
|
if(a.name < b.name) {
|
|
return -1
|
|
}
|
|
return 1
|
|
}
|
|
|
|
//Update export hook for glslify-live
|
|
proto.update = function(
|
|
vertSource
|
|
, fragSource
|
|
, uniforms
|
|
, attributes) {
|
|
|
|
//If only one object passed, assume glslify style output
|
|
if(!fragSource || arguments.length === 1) {
|
|
var obj = vertSource
|
|
vertSource = obj.vertex
|
|
fragSource = obj.fragment
|
|
uniforms = obj.uniforms
|
|
attributes = obj.attributes
|
|
}
|
|
|
|
var wrapper = this
|
|
var gl = wrapper.gl
|
|
|
|
//Compile vertex and fragment shaders
|
|
var pvref = wrapper._vref
|
|
wrapper._vref = shaderCache.shader(gl, gl.VERTEX_SHADER, vertSource)
|
|
if(pvref) {
|
|
pvref.dispose()
|
|
}
|
|
wrapper.vertShader = wrapper._vref.shader
|
|
var pfref = this._fref
|
|
wrapper._fref = shaderCache.shader(gl, gl.FRAGMENT_SHADER, fragSource)
|
|
if(pfref) {
|
|
pfref.dispose()
|
|
}
|
|
wrapper.fragShader = wrapper._fref.shader
|
|
|
|
//If uniforms/attributes is not specified, use RT reflection
|
|
if(!uniforms || !attributes) {
|
|
|
|
//Create initial test program
|
|
var testProgram = gl.createProgram()
|
|
gl.attachShader(testProgram, wrapper.fragShader)
|
|
gl.attachShader(testProgram, wrapper.vertShader)
|
|
gl.linkProgram(testProgram)
|
|
if(!gl.getProgramParameter(testProgram, gl.LINK_STATUS)) {
|
|
var errLog = gl.getProgramInfoLog(testProgram)
|
|
throw new GLError(errLog, 'Error linking program:' + errLog)
|
|
}
|
|
|
|
//Load data from runtime
|
|
uniforms = uniforms || runtime.uniforms(gl, testProgram)
|
|
attributes = attributes || runtime.attributes(gl, testProgram)
|
|
|
|
//Release test program
|
|
gl.deleteProgram(testProgram)
|
|
}
|
|
|
|
//Sort attributes lexicographically
|
|
// overrides undefined WebGL behavior for attribute locations
|
|
attributes = attributes.slice()
|
|
attributes.sort(compareAttributes)
|
|
|
|
//Convert attribute types, read out locations
|
|
var attributeUnpacked = []
|
|
var attributeNames = []
|
|
var attributeLocations = []
|
|
var i
|
|
for(i=0; i<attributes.length; ++i) {
|
|
var attr = attributes[i]
|
|
if(attr.type.indexOf('mat') >= 0) {
|
|
var size = attr.type.charAt(attr.type.length-1)|0
|
|
var locVector = new Array(size)
|
|
for(var j=0; j<size; ++j) {
|
|
locVector[j] = attributeLocations.length
|
|
attributeNames.push(attr.name + '[' + j + ']')
|
|
if(typeof attr.location === 'number') {
|
|
attributeLocations.push(attr.location + j)
|
|
} else if(Array.isArray(attr.location) &&
|
|
attr.location.length === size &&
|
|
typeof attr.location[j] === 'number') {
|
|
attributeLocations.push(attr.location[j]|0)
|
|
} else {
|
|
attributeLocations.push(-1)
|
|
}
|
|
}
|
|
attributeUnpacked.push({
|
|
name: attr.name,
|
|
type: attr.type,
|
|
locations: locVector
|
|
})
|
|
} else {
|
|
attributeUnpacked.push({
|
|
name: attr.name,
|
|
type: attr.type,
|
|
locations: [ attributeLocations.length ]
|
|
})
|
|
attributeNames.push(attr.name)
|
|
if(typeof attr.location === 'number') {
|
|
attributeLocations.push(attr.location|0)
|
|
} else {
|
|
attributeLocations.push(-1)
|
|
}
|
|
}
|
|
}
|
|
|
|
//For all unspecified attributes, assign them lexicographically min attribute
|
|
var curLocation = 0
|
|
for(i=0; i<attributeLocations.length; ++i) {
|
|
if(attributeLocations[i] < 0) {
|
|
while(attributeLocations.indexOf(curLocation) >= 0) {
|
|
curLocation += 1
|
|
}
|
|
attributeLocations[i] = curLocation
|
|
}
|
|
}
|
|
|
|
//Rebuild program and recompute all uniform locations
|
|
var uniformLocations = new Array(uniforms.length)
|
|
function relink() {
|
|
wrapper.program = shaderCache.program(
|
|
gl
|
|
, wrapper._vref
|
|
, wrapper._fref
|
|
, attributeNames
|
|
, attributeLocations)
|
|
|
|
for(var i=0; i<uniforms.length; ++i) {
|
|
uniformLocations[i] = gl.getUniformLocation(
|
|
wrapper.program
|
|
, uniforms[i].name)
|
|
}
|
|
}
|
|
|
|
//Perform initial linking, reuse program used for reflection
|
|
relink()
|
|
|
|
//Save relinking procedure, defer until runtime
|
|
wrapper._relink = relink
|
|
|
|
//Generate type info
|
|
wrapper.types = {
|
|
uniforms: makeReflect(uniforms),
|
|
attributes: makeReflect(attributes)
|
|
}
|
|
|
|
//Generate attribute wrappers
|
|
wrapper.attributes = createAttributeWrapper(
|
|
gl
|
|
, wrapper
|
|
, attributeUnpacked
|
|
, attributeLocations)
|
|
|
|
//Generate uniform wrappers
|
|
Object.defineProperty(wrapper, 'uniforms', createUniformWrapper(
|
|
gl
|
|
, wrapper
|
|
, uniforms
|
|
, uniformLocations))
|
|
}
|
|
|
|
//Compiles and links a shader program with the given attribute and vertex list
|
|
function createShader(
|
|
gl
|
|
, vertSource
|
|
, fragSource
|
|
, uniforms
|
|
, attributes) {
|
|
|
|
var shader = new Shader(gl)
|
|
|
|
shader.update(
|
|
vertSource
|
|
, fragSource
|
|
, uniforms
|
|
, attributes)
|
|
|
|
return shader
|
|
}
|
|
|
|
module.exports = createShader
|
|
|