dreemgl
Version:
DreemGL is an open-source multi-screen prototyping framework for mediated environments, with a visual editor and shader styling for webGL and DALi runtimes written in JavaScript. As a toolkit for gpu-accelerated multiscreen development, DreemGL includes
746 lines (668 loc) • 24.4 kB
JavaScript
/* DreemGL is a collaboration between Teeming Society & Samsung Electronics, sponsored by Samsung and others.
Copyright 2015-2016 Teeming Society. Licensed under the Apache License, Version 2.0 (the "License"); You may not use this file except in compliance with the License.
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.*/
define.class(function(require, exports){
var OneJSParser = require('$system/parse/onejsparser')
var GLSLGen = require('./glslgen')
var gltypes = require('./gltypes')
var dump = require('$system/parse/astdumper')
var astdef = require('$system/parse/onejsdef')
//this.default_texture = GLTexture.fromArray(new Float32Array(4*4*4), 4,4)
this.noise = require('$system/shaderlib/noiselib')
this.pal = require('$system/shaderlib/palettelib')
this.shape = require('$system/shaderlib/shapelib')
this.math = require('$system/shaderlib/mathlib')
this.demo = require('$system/shaderlib/demolib')
this.material = require('$system/shaderlib/materiallib')
this.colorlib = require('$system/shaderlib/colorlib')
this.RAD = '1'
this.DEG = '0.017453292519943295'
this.PI = '3.141592653589793'
this.PI2 = '6.283185307179586'
this.E = '2.718281828459045'
this.LN2 = '0.6931471805599453'
this.LN10 = '2.302585092994046'
this.LOG2E = '1.4426950408889634'
this.LOG10E = '0.4342944819032518'
this.SQRT_1_2 = '0.70710678118654757'
this.SQRT2 = '1.4142135623730951'
this.visible = true
this.pickalpha = 0.01
// we can use singletons of these stateless classes
var onejsparser = new OneJSParser()
onejsparser.parser_cache = {}
var glslgen = new GLSLGen()
this._atConstructor = function(){
this.view = this.outer
}
this.set_precision = 'precision highp float;\n'
this.set_extensions = '#extension GL_OES_standard_derivatives : enable\n'
this.compileHeader = function(){
var ret = '';
if(this.set_extensions) ret += this.set_extensions
if(this.set_precision) ret += this.set_precision
return ret + '\n'
}
this.compileAttributes = function(vtxattr, pixattr){
var ret = ''
var attr = {}
if(vtxattr) for(var key in vtxattr){
var gltype = gltypes.getType(vtxattr[key])
ret += 'attribute ' + gltype + ' _' + key + ';\n'
attr[key] = gltype
}
if(pixattr) for(var key in pixattr) if(!(key in vtxattr)){
var gltype = gltypes.getType(pixattr[key])
ret += 'attribute ' + gltype + ' _' + key + ';\n'
attr[key] = gltype
}
for(var key in attr){
var gltype = attr[key]
// ok so if key is not in pixattr, its a normal one
if(!pixattr || !(key in pixattr)){
ret += gltype + ' ' + key + ';\n'
}
else{
ret += 'varying ' + gltype + ' ' + key + ';\n'
}
}
return ret
}
this.compileAttribRename = function(vtxattr, pixattr){
var ret = ''
if(vtxattr) for(var key in vtxattr){
ret += '\t' + key + ' = _' + key + ';\n'
}
if(pixattr) for(var key in pixattr) if(!(key in vtxattr)){
ret += '\t' + key + ' = _' + key + ';\n'
}
return ret
}
this.compileVaryings = function(varyings, name){
var ret = ''
for(var key in varyings){
var gltype = gltypes.getType(varyings[key])
ret += 'varying ' + gltype + ' ' + key + ';\n'
}
if(ret) ret = '//------------------- '+name+' -------------------\n'+ret+'\n'
return ret
}
this.compileUniforms = function(uniforms){
var ret = ''
for(var key in uniforms){
var gltype = gltypes.getType(uniforms[key])
ret += 'uniform ' + gltype + ' _' + key + ';\n'
ret += gltype + ' ' + key + ';\n'
}
if(ret) ret = '//------------------- Uniforms -------------------\n'+ret+'\n'
return ret
}
this.compileUniformRename = function(uniforms){
var ret = ''
for(var key in uniforms){
ret += '\t' + key + ' = _' + key + ';\n'
}
return ret
}
this.compileFunctions = function(call, mask){
var ret = ''
var init
if(!mask) mask = {}, init = true
if(call.name in mask) return ''
mask[call.name] = 1
// output dependencies first
for(var key in call.deps){
var dep = call.deps[key]
ret += this.compileFunctions(dep, mask)
}
if(call.code) ret += '\n'+call.code +'\n'
if(init) ret = '//------------------- Functions -------------------' + ret + '\n'
return ret
}
this.compileTextures = function(textures){
var ret = ''
for(var key in textures){
ret += 'uniform sampler2D ' + key + ';\n'
}
if(ret) ret = '//------------------- Textures -------------------\n'+ret+'\n'
return ret
}
this.compileStructs = function(structs){
var ret = ''
for(var key in structs){
var struct = structs[key]
// ok so.. we need to write the struct
ret += 'struct ' + key + '{\n'
var defs = struct.def
for(var slotname in defs){
var slot = defs[slotname]
if(typeof slot === 'function'){
ret += '\t' + gltypes.getType(slot) + ' ' + slotname + ';\n'
}
}
ret += '};\n'
}
if(ret) ret = '\n//------------------- Structs -------------------\n'+ret+'\n'
return ret
}
this.mapUniforms = function(gl, shader, uniforms, uniset, unilocs){
for(var key in uniforms) if(!uniset[key]){
var type = gltypes.getType(uniforms[key])
uniset[key] = gltypes.uniforms[type]
var loc = unilocs[key] = {
type: type,
loc:gl.getUniformLocation(shader, '_' + key)
}
if(key.indexOf('_DOT_') !== -1) loc.split = key.split(/_DOT_/)
}
}
this.mapTextures = function(gl, shader, textures, texlocs){
for(var key in textures){
var tex = textures[key]
var loc = texlocs[key] = {
loc: gl.getUniformLocation(shader, key),
samplerdef: tex.samplerdef,
samplerid: tex.samplerid,
name: tex.name
}
if(tex.name.indexOf('_DOT_') !== -1) loc.split = tex.name.split(/_DOT_/)
}
}
this.mapAttributes = function(gl, shader, attributes, attrlocs, context){
for(var key in attributes){
var loc = attrlocs[key] = {
loc:gl.getAttribLocation(shader, '_' + key)
}
if(key.indexOf('_DOT_') !== -1){
// okay lets look up the type
var split = key.split(/_DOT_/)
// ok so we need to look up split[0] on context
var name = loc.name = split[0]
var geom = context[name]
var last = geom.struct
var offset = 0
for(var i = 1; i < split.length; i++){
// lets find split on our struct
var info = last.keyInfo(split[i])
offset += info.offset
last = info.type
}
if(!last) throw new Error('Cannot find attribute ' + key)
loc.slots = last.slots
loc.offset = offset
}
}
}
this.annotateLines = function(text){
var lines = text.split(/\n/)
var ret = ''
for(var i = 0; i < lines.length; i++){
ret += (i+1)+': '+lines[i] + '\n'
}
return ret
}
this.toVec4 = function(str, ast, str2, ast2){
if(ast.infer === vec4){
if(ast2 && ast2.infer === float32){
return '('+str+')*vec4(1.,1.,1.,'+str2+')'
}
return str
}
if(ast.infer === vec3){
if(ast2 && ast2.infer === float32){
return 'vec4('+str+','+str2+')'
}
return 'vec4(' + str + ',1.)'
}
if(ast.infer === vec2) return 'vec4(' + str + ',0.,1.)'
if(ast.infer === float32) return '(' + str + ').xxxx'
return str
}
this.decodeBlendFactor = function(node, key){
var gl = gltypes.gl
if(node.type == 'Id') return gl.ONE
if(node.type == 'Binary'){
var factor = node.left
if(node.right.name != key) throw new Error('Blend equation needs to have either pixel or frame on the right side of the *')
if(factor.type == 'Binary'){ // its a one minus situation
if(factor.op != '-' || factor.left.type != 'Value' || factor.left.value != 1) throw new Error('Invalid blending (only 1- supported)')
var name = factor.right.name
if(name === 'src_alpha') return gl.ONE_MINUS_SRC_ALPHA
if(name === 'src_color') return gl.ONE_MINUS_SRC_COLOR
if(name === 'dst_color') return gl.ONE_MINUS_DST_COLOR
if(name === 'dst_alpha') return gl.ONE_MINUS_DST_ALPHA
if(name === 'constant_color') return GL.ONE_MINUS_CONSTANT_COLOR
if(name === 'constant_alpha') return GL.ONE_MINUS_CONSTANT_ALPHA
throw new Error('implement one minus mode')
}
if(factor.type != 'Id') throw new Error('Invalid blending (factor not an Id)')
var name = factor.name
if(name === 'src_alpha') return gl.SRC_ALPHA
if(name === 'src_color') return gl.SRC_COLOR
if(name === 'dst_color') return gl.DST_COLOR
if(name === 'dst_alpha') return gl.DST_ALPHA
if(name === 'constant_color') return GL.CONSTANT_COLOR
if(name === 'constant_alpha') return GL.CONSTANT_ALPHA
// todo constant color and constant alpha
}
throw new Error('Invalid blending factor (node type invalid)')
}
this.decodeBlendEquation = function(eq, value){
var gl = gltypes.gl
var out = {original:value}
if(!eq) return out
if(eq.type == 'Binary' && (eq.op == '+' || eq.op == '-')){ // its the main equation
var left = eq.left
var right = eq.right
if(eq.op == '+') out.op = gl.FUNC_ADD
else if(eq.op == '-') out.op = gl.FUNC_SUBTRACT
if(left.type == 'Id' && left.name == 'src_color' ||
left.type == 'Binary' && left.right.name == 'src_color'){
left = eq.right, right = eq.left
if(eq.op == '-') out.op = gl.FUNC_REVERSE_SUBTRACT
}
// left should be frame, right should be pixel
out.dst = this.decodeBlendFactor(left, 'dst_color')
out.src = this.decodeBlendFactor(right, 'src_color')
}
else if(eq.type == 'Binary' && eq.op == '*'){ // its a single mul
out.op = gl.FUNC_ADD
// the right side needs to be either frame or pixel
if(eq.right.name == 'dst_color'){
out.src = gl.ZERO
out.dst = this.decodeBlendFactor(eq, 'dst_color')
}
else if(eq.right.name == 'src_color'){
out.dst = gl.ZERO
out.src = this.decodeBlendFactor(eq, 'src_color')
}
else throw new Error('Blend equation needs to have either pixel or frame on the right side of the *')
}
else if(eq.type == 'Id'){
out.op = gl.FUNC_ADD
if(eq.name == 'dst_color'){
out.src = gl.ZERO
out.dst = gl.ONE
}
else if(eq.name == 'src_color'){
out.src = gl.ONE
out.dst = gl.ZERO
}
else {
throw new Error('Blend equation invalid (not frame or pixel)')
}
}
else throw new Error('Blend equation invalid (main type) ' + eq.type + ' ' + eq.op)
return out
}
this.decodeDepthEquation = function(eq, value){
var out = {original:value, func:0}
if(!eq) return out
if(eq.type === 'Id' && eq.name === 'disabled'){
out.func = 1
return out
}
if(eq.type == 'Logic'){
if(eq.left.name == 'src_depth' && eq.right.name == 'dst_depth'){
out.func = gltypes.compare[eq.op]
return out
}
else if(eq.left.name == 'src_depth' && eq.right.name == 'dst_depth'){
out.func = gltypes.complement[eq.op]
return out
}
}
throw new Error('depth eqation not in "src_depth < dst_depth" format')
}
this.decodeStencilEquation = function(gl, eq, value){
if(!eq) return {}
else
if(eq.type == 'Value'){
}
}
var blend_eq_cache = {}
// lets define the blending equation setters
Object.defineProperty(this, 'color_blend', {
get:function(){ return this.color_blend_eq && this.color_blend_eq.original },
set:function(value){
this.color_blend_eq = blend_eq_cache[value] || (blend_eq_cache[value] = this.decodeBlendEquation(onejsparser.parse(value).steps[0], value))
}
})
Object.defineProperty(this, 'alpha_blend', {
get:function(){ return this.alpha_blend_eq && this.alpha_blend_eq.original },
set:function(value){
this.alpha_blend_eq = blend_eq_cache[value] || (blend_eq_cache[value] = this.decodeBlendEquation(onejsparser.parse(value).steps[0], value))
}
})
var depth_eq_cache = {}
Object.defineProperty(this, 'depth_test', {
get:function(){ return this.depth_test_eq && this.depth_test_eq.original },
set:function(value){
this.depth_test_eq = depth_eq_cache[value] || (depth_eq_cache[value] = this.decodeDepthEquation(onejsparser.parse(value).steps[0], value))
}
})
this.alpha_blend = ''
//this.depth_test = 'src_depth > dst_depth'
this.depth_test = ''
this.depth_mask = true
this.color_blend = '(1 - src_alpha) * dst_color + src_alpha * src_color'
this.alpha = ''
this.color = vec4(0,1,0,1)
this.position = function(){
return vec4(0,0,0,0)
}
this.has_pick = true
this.update_dirty = true
this.reupdate = function(){
if(!this.update_dirty){
this.update_dirty = true
if(this.view && !this.view.update_dirty){
this.view.update_dirty = true
this.view.redraw()
}
}
}
var ignore_compare = {
outer:1,
view:1,
shadername:1,
order:1,
shader:1,
update_dirty:1,
dirty_props:1,
pix_state:1,
vtx_state:1,
_view_listeners:1,
pickguid:1
}
this.isShaderEqual = function(prevshader, view, prev){
// lets compare the prevshader.view vs my view
var array = prevshader.view_functions
if(array) for(var i = 0; i < array.length; i++){
var key = array[i]
var vfn = view[key], pfn = prev[key]
if(!vfn || !pfn || vfn.toString() !== pfn.toString()){
return false
}
}
for(var key in this){
if(key in ignore_compare) continue
if(this.__lookupSetter__(key)) continue
// we also have to ignore geometry..
var value = this[key]
var other = prevshader[key]
// check type
if(!(value && value.struct && !value.struct.equals || // geometry object
value && value.struct && other && other.struct && value.struct.equals && value.struct.equals(value, other) || // vector type
typeof value === 'function' && typeof other === 'function' && value.toString() === other.toString() || value === other)){ // function
return false
}
}
return true
}
this.monitorCompiledProperty = function(name){
if(this.__lookupSetter__(name)) return
var get = '_' + name
this[get] = this[name]
Object.defineProperty(this, name, {
enumerable:false,
configurable:false,
get:function(){
return this[get]
},
set:function(value){
if(this[get] === value) return
this.dirty = true
if(!this.hasOwnProperty('dirty_props')) this.dirty_props = []
this.dirty_props.push(name)
// trigger a recompile
if(this.hasOwnProperty('shader')) this.shader = undefined
this[get] = value
}
})
}
this.getLocations = function(gl, shader, vtx_state, pix_state){
// get uniform locations
var uniset = shader.uniset = {}
var unilocs = shader.unilocs = {}
var refattr = shader.refattr = {}
for(var key in vtx_state.reference_is_attr) refattr[key] = 1
for(var key in pix_state.reference_is_attr) refattr[key] = 1
this.mapUniforms(gl, shader, vtx_state.uniforms, uniset, unilocs)
this.mapUniforms(gl, shader, pix_state.uniforms, uniset, unilocs)
// lets get sampler2D uniforms
var texlocs = shader.texlocs = {}
this.mapTextures(gl, shader, vtx_state.textures, texlocs)
this.mapTextures(gl, shader, pix_state.textures, texlocs)
// get attribute locations
var attrlocs = shader.attrlocs = {}
this.mapAttributes(gl, shader, vtx_state.attributes, attrlocs, this)
this.mapAttributes(gl, shader, pix_state.attributes, attrlocs, this)
}
// compile the shader
this.compile = function(gldevice){
if(gldevice && this.dirty === false){
// lets walk up the prototype chain till we hit dirty === false
var proto = this
while(!proto.hasOwnProperty('dirty')){
proto = Object.getPrototypeOf(proto)
}
if(!proto.hasOwnProperty('shader')){
this.shader = proto.shader = this.compileShader(gldevice)
}
else{
this.shader = proto.shader
}
return
}
// lets run the type inferencer on the pixel shader
var vtx_ast = onejsparser.parse(this.position).steps[0]
if(vtx_ast.type == 'Function') vtx_ast = onejsparser.parse('position()').steps[0]
// ok lets run the vertex codegen.
var vtx_state = glslgen.newState(this)
var vtx_code = glslgen.expand(vtx_ast, undefined, vtx_state)
// pixel
var pix_state = glslgen.newState(this, vtx_state.varyings)
// support both immediate and expression color
if(this.color === undefined){
return
}
if(typeof this.color === 'object'){
if(this.color.length == 3) var pix_ast = {infer:vec3}
else var pix_ast = {infer:vec4}
var pix_code = '_color'
pix_state.uniforms.color = pix_ast.infer
}
else{
var pix_ast = onejsparser.parse(this.color).steps[0]
if(pix_ast.type == 'Function') pix_ast = onejsparser.parse('color()').steps[0]
var pix_code = glslgen.expand(pix_ast, undefined, pix_state)
}
// support imediate alpha value and alpha expressions
if(typeof this.alpha === 'number'){
pix_state.uniforms.alpha = float32
var alpha_ast = {infer:float32}
var alpha_code = '_alpha'
}
else{
var alpha_ast = onejsparser.parse(this.alpha).steps[0]
var alpha_code = ''
if(alpha_ast && alpha_ast.type == 'Function') alpha_ast = onejsparser.parse('alpha()').steps[0]
if(alpha_ast){
alpha_code = glslgen.expand(alpha_ast, undefined, pix_state)
}
}
var vtx = ''
// if we have attributes in the pixelshader, we have to forward em
// what we can do is if we have pix_attr we make them varying
// lets generate the vertex shader
vtx += this.compileHeader()
vtx += this.compileStructs(vtx_state.structs)
vtx += this.compileAttributes(vtx_state.attributes, pix_state.attributes)
vtx += this.compileVaryings(vtx_state.varyings, 'Varyings')
vtx += this.compileUniforms(vtx_state.uniforms)
vtx += this.compileTextures(vtx_state.textures)
vtx += this.compileFunctions(vtx_state.call)
vtx += '//------------------- Vertex shader main -------------------\nvoid main(){\n'
vtx += this.compileUniformRename(vtx_state.uniforms)
vtx += this.compileAttribRename(vtx_state.attributes, pix_state.attributes)
vtx += '\tgl_Position = ' + this.toVec4(vtx_code, vtx_ast) + ';\n'
vtx += '}\n'
var pix_base = '', pix_color = '', pix_pick = '', pix_debug = ''
pix_base += this.compileHeader()
if(pix_state.debug.type){
this.debug_type = gltypes.getType(pix_state.debug.type)
pix_base += this.debug_type + ' dbg;\n'
}
if(pix_state.dump.set){
pix_base += 'vec4 dump;\n'
}
pix_base += 'float PickGuid = 0.;\n'
pix_base += this.compileStructs(pix_state.structs)
pix_base += this.compileVaryings(pix_state.attributes, 'Attribute varyings')
pix_base += this.compileVaryings(pix_state.varyings, 'Varyings')
pix_base += this.compileUniforms(pix_state.uniforms)
pix_base += this.compileTextures(pix_state.textures)
pix_base += this.compileFunctions(pix_state.call)
if(this.debug_type){
pix_debug += pix_base
pix_debug += '//------------------- Debug Pixel shader main -------------------\nvoid main(){\n'
pix_debug += this.compileUniformRename(pix_state.uniforms)
if(this.debug_type == 'int') pix_debug += '\tdbg = 20;\n'
if(this.debug_type == 'float') pix_debug += '\tdbg = 20.;\n'
if(this.debug_type == 'vec2') pix_debug += '\tdbg = vec2(.2,.2);\n'
if(this.debug_type == 'ivec2') pix_debug += '\tdbg = ivec2(20,20);\n'
if(this.debug_type == 'vec3') pix_debug += '\tdbg = vec3(.2,.2,.2);\n'
if(this.debug_type == 'ivec3') pix_debug += '\tdbg = ivec3(20,20);\n'
pix_debug += '\t' + this.toVec4(pix_code, pix_ast, alpha_code, alpha_ast) + ';\n'
if(this.debug_type == 'int') pix_debug += '\tgl_FragColor = vec4(mod(abs(float(dbg)),256.)/255.,abs(float(dbg/256))/256.,dbg >= 0? 1.: 0.,1.);\n'
if(this.debug_type == 'float') pix_debug += '\tgl_FragColor = vec4(mod(abs(dbg),1.),float(floor(abs(dbg))/256.),dbg >= 0.? 1.: 0.,1.);\n'
if(this.debug_type == 'vec2') pix_debug += '\tgl_FragColor = vec4(clamp(dbg.x,0.,1.),clamp(dbg.y,0.,1.),0,1.);\n'
if(this.debug_type == 'ivec2') pix_debug += '\tgl_FragColor = vec4(float(dbg.x)/255.,float(dbg.y)/255.,0,1.);\n'
if(this.debug_type == 'vec3') pix_debug += '\tgl_FragColor = vec4(clamp(dbg.x,0.,1.),clamp(dbg.y,0.,1.),clamp(dbg.z,0.,1.),1.);\n'
if(this.debug_type == 'ivec3') pix_debug += '\tgl_FragColor = vec4(float(dbg.x)/255.,float(dbg.y)/255.,float(dbg.z)/255.,1.);\n'
pix_debug += '}\n'
}
pix_color += pix_base
pix_color += '//------------------- Color Pixel shader main -------------------\nvoid main(){\n'
pix_color += this.compileUniformRename(pix_state.uniforms)
if(pix_state.dump.set){
pix_color += '\tdump = vec4(.5,.5,.5,1.);\n'
}
pix_color += '\tgl_FragColor = ' + this.toVec4(pix_code, pix_ast, alpha_code, alpha_ast) + ';\n'
if(pix_state.dump.set){
pix_color += '\tgl_FragColor = dump;\n'
}
pix_color += '}\n'
pix_pick += pix_base
pix_pick += 'uniform vec3 _pickguid;\n'
pix_pick += 'uniform float _pickalpha;\n'
pix_pick += '//------------------- Pick Pixel shader main -------------------\nvoid main(){\n'
pix_pick += this.compileUniformRename(pix_state.uniforms)
pix_pick += '\tvec4 col = ' + this.toVec4(pix_code, pix_ast, alpha_code, alpha_ast) + ';\n'
pix_pick += '\tfloat _pickguid2 = (_pickguid.y * 255. + _pickguid.z * 255.*256.) - PickGuid;\n'
pix_pick += '\tgl_FragColor = vec4(_pickguid.x, mod(_pickguid2,256.)/255., floor(_pickguid2/256.)/255., col.a>_pickalpha?1.:0.);\n'
pix_pick += '}\n'
if(this.dump){
console.log(vtx)
console.log(pix_color)
console.log(pix_pick)
console.log(pix_debug)
}
vtx_state.code = vtx
pix_state.code_color = pix_color
pix_state.code_pick = pix_pick
pix_state.code_debug = pix_debug
this.pix_state = pix_state
this.vtx_state = vtx_state
//if(!this.device){
// turn shader into dirty observed thing
// lets look at our local funciton refs
for(var key in vtx_state.functions){
var name = vtx_state.functions[key].undecorated
if(name.indexOf('_DOT_') === -1) this.monitorCompiledProperty(name)
}
for(var key in pix_state.functions){
var name = pix_state.functions[key].undecorated
if(name.indexOf('_DOT_') === -1) this.monitorCompiledProperty(name)
}
this.dirty = false
if(!gldevice){
return
}
this.shader = this.compileShader(gldevice)
this.connectWires()
}
this.atExtend = function(){
var shader = this
if(define.$platform === 'nodejs') return
// forwar d the view reference
if(this.constructor.outer){
this.view = this.constructor.outer
this.compile()
// lets put listeners on our view so when a view uniform modifies it redraws the node
for(var key in this.pix_state.uniforms){
var parts = key.split('_DOT_')
if(parts.length === 2 && parts[0] === 'view'){
if('_' + parts[1] in this.view){
this.view.addListener(parts[1], function(){
this.redraw()
})
}
}
}
for(var key in this.vtx_state.uniforms){
var parts = key.split('_DOT_')
if(parts.length === 2 && parts[0] === 'view'){
if('_' + parts[1] in this.view){
this.view.addListener(parts[1], function(){
this.redraw()
})
}
}
}
var name = shader.constructor.name
function recompile_shader(){
var oldcls = this[name]
this[name] = {dirty:true}
var newcls = this[name]
for(var key in this.shader_enable){
if(key !== name && this[key] === oldcls){
// overwrite references
this[key] = newcls
}
}
}
recompile_shader.shader = name
this.view_functions = []
for(var key in this.vtx_state.functions){
var parts = key.split('_DOT_')
if(parts.length === 2 && parts[0] === 'view'){
var left = parts[1].split('_T_')[0]
// ok lets hook this thing to invalidate our shader
if(!this.view.hasListenerProp(left, 'shader', name)){
this.view_functions.push(left)
this.view.addListener(left, recompile_shader)
}
}
}
for(var key in this.pix_state.functions){
var parts = key.split('_DOT_')
if(parts.length === 2 && parts[0] === 'view'){
var left = parts[1].split('_T_')[0]
// ok lets hook this thing to invalidate our shader
if(!this.view.hasListenerProp(left, 'shader', name)){
this.view_functions.push(left)
this.view.addListener(left, recompile_shader)
}
}
}
// lets put other listeners on our referenced function of view
// and if they fire, we need to inherit in place and set dirty=true
//console.log(this.pix_state.code_color)
}
else if(this !== exports.prototype) this.compile()
}
})