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
639 lines (535 loc) • 22.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('$system/base/shader', function(require, exports){
var gltypes = require('$system/base/gltypes')
exports.Texture =
this.Texture = require('./texturedali')
util = require('util');
// DaliApi is a static object to access the dali api
DaliApi = require('./dali_api')
// DaliDreemgl is the interface between dreemgl and dali.
DaliShader = require('./dali_shader')
DaliActor = require('./dali_actor')
/**
* @method compileShader
* Compiles the shader, or use the cached version.
* Construct a mesh actor if necessary and attach to the view
* The 'this' pointer is an object like border or hardrect
* @param {Object} gldevice Instance of DeviceDali
* @return {Object} shader Object containing compiled shader information.
* In webgl this is an object returned by gl.createProgram
* In dali, this is a hash containing a dali_shader object
*/
this.compileShader = function(gldevice){
//console.log('*#*#*#*# compileShader', this.view ? this.view.id : '<SCREEN>');
var vtx_state = this.vtx_state
var pix_state = this.pix_state
var vtx_code = vtx_state.code
//console.log('vtx_code', vtx_code);
//console.log('pix_code', pix_state.code_color);
//console.log('====== vtx_state call', vtx_state.call);
var pix_color = pix_state.code_color
var pix_pick = pix_state.code_pick
var pix_debug = pix_state.code_debug
var gl = gldevice.gl
var cache_id = vtx_code + pix_color + this.has_pick
// Get the DaliShader object from a cache, or build one
shader = gldevice.shadercache[cache_id]
//if(shader) return this.dalishader
if (!shader) {
// shader is a hash of compiled information and dali objects
shader = {
object_type: '(compiled_shader_data)'
,debug: {}
,pick: {}
,uniset: {}
,unilocks: {}
,refattr: {}
,texlocs: {}
};
// Build a DaliShader object and attach to shader
var shadercode = vtx_state.code;
var fragcode = pix_state.code_color;
shader.dalishader = new DaliShader(shadercode, fragcode);
//DEV
// Compile the dali objects
//shader.compileShader(this, dalishader);
//Not used by Dali
// var vtx_shader = gl.createShader(gl.VERTEX_SHADER)
// gl.shaderSource(vtx_shader, vtx_code)
// gl.compileShader(vtx_shader)
// if (!gl.getShaderParameter(vtx_shader, gl.COMPILE_STATUS)){
// var err = gl.getShaderInfoLog(vtx_shader)
// console.error(err.toString(), this.annotateLines(vtx_code))
// return
// //throw new Error(err)
// }
//
// // compile the shader
// var pix_color_shader = gl.createShader(gl.FRAGMENT_SHADER)
// gl.shaderSource(pix_color_shader, pix_color)
// gl.compileShader(pix_color_shader)
// if (!gl.getShaderParameter(pix_color_shader, gl.COMPILE_STATUS)){
// var err = gl.getShaderInfoLog(pix_color_shader)
//
// console.error(err.toString(), this.annotateLines(pix_color))
// return
// //throw new Error(err)
// }
//
// shader = gldevice.shadercache[cache_id] = gl.createProgram()
// gl.attachShader(shader, vtx_shader)
// gl.attachShader(shader, pix_color_shader)
// gl.linkProgram(shader)
// Build information on uniforms, textures, and attributes
this.getLocations(gl, shader, vtx_state, pix_state)
//console.log('*** COMPILED ***');
//console.log('unilocks', shader.unilocks);
//console.log('uniset', shader.uniset);
//console.log('refattr', shader.refattr);
//console.log('texlocs', shader.texlocs);
//TODO. Remove?
this.compile_use = true
if(this.compile_use) this.compileUse(shader)
gldevice.shadercache[cache_id] = shader
//Not supported by Dali (Yet)
// if(pix_debug){
// // compile the pick shader
// var pix_debug_shader = gl.createShader(gl.FRAGMENT_SHADER)
// gl.shaderSource(pix_debug_shader, pix_debug)
// gl.compileShader(pix_debug_shader)
// if (!gl.getShaderParameter(pix_debug_shader, gl.COMPILE_STATUS)){
// var err = gl.getShaderInfoLog(pix_debug_shader)
// console.log(err.toString(), this.annotateLines(pix_debug))
// throw new Error(err)
// }
//
// shader.debug = gl.createProgram()
// gl.attachShader(shader.debug, vtx_shader)
// gl.attachShader(shader.debug, pix_debug_shader)
// gl.linkProgram(shader.debug)
// // add our pick uniform
// this.getLocations(gl, shader.debug, vtx_state, pix_state)
// if(this.compile_use) this.compileUse(shader.debug)
// }
//
// if(this.has_pick){
// // compile the pick shader
// var pix_pick_shader = gl.createShader(gl.FRAGMENT_SHADER)
// gl.shaderSource(pix_pick_shader, pix_pick)
// gl.compileShader(pix_pick_shader)
// if (!gl.getShaderParameter(pix_pick_shader, gl.COMPILE_STATUS)){
// var err = gl.getShaderInfoLog(pix_pick_shader)
//
// console.log(err.toString(), this.annotateLines(pix))
// throw new Error(err)
// }
//
// shader.pick = gl.createProgram()
// gl.attachShader(shader.pick, vtx_shader)
// gl.attachShader(shader.pick, pix_pick_shader)
// gl.linkProgram(shader.pick)
// // add our pick uniform
// pix_state.uniforms['pickguid'] = vec3
//
// this.getLocations(gl, shader.pick, vtx_state, pix_state)
//
// if(this.compile_use) this.compileUse(shader.pick)
// }
} // if (!this.dalishader) {
// Build missing dali objects (if they don't exist)
//console.log('shader', shader.object_type, shader);
//console.trace('CALLING createDaliObjects');
DaliApi.createDaliObjects(shader, this); // shader);
//console.log('shader has', Object.keys(shader));
//DaliApi.createDaliActor(this, shader);
//console.log('---- ---- ---- ADDING TEXTURE INFO');
//shader.addAttributeGeometry(this, shader.attrlocs);
return shader
}
this.useShader = function(gl, shader){
if(shader.use) return shader.use(gl, shader, this)
console.log('***************************************************************************************************OLD CODE RUNNING');
}
this.compile_use = true
// Override from shader.js (DALI)
this.mapUniforms = function(gl, shader, uniforms, uniset, unilocs){
// dali uses registerAnimatableProperty to set a uniform
for(var key in uniforms) if(!uniset[key]){
var type = gltypes.getType(uniforms[key])
//uniset[key] = gltypes.uniforms[type]
uniset[key] = gltypes.uniforms[type]
var loc = unilocs[key] = {
type: type,
loc: key // Store the name, not the location
}
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: key, // Store the name, not the location
samplerdef: tex.samplerdef,
samplerid: tex.samplerid,
name: tex.name
}
if(tex.name.indexOf('_DOT_') !== -1) loc.split = tex.name.split(/_DOT_/)
}
}
// Template for generated code
// {object} gl stubbed out gl object
// {object} shader compiled shader object, containing dalishader
// and daligeometry. (see compileShader in this file)
// {object} root display object (ex. border, hardrect), containing
// dalimaterial, dalirenderer, daliactor.
this.useShaderTemplate = function(gl, shader, root){
// Create dali objects when first used
if (root && !root.daliactor) {
DaliApi.createDaliActor(root, shader);
}
//console.log('useShader', root.view ? root.view.id : 'screen', 'shader', shader.object_type, 'root', root.object_type)
// use the shader
gl.useProgram(shader)
var dali = DaliApi.dali
var daliactor = root ? root.daliactor : undefined;
var dalimaterial = root ? root.dalimaterial : undefined;
var daligeometry = root.daligeometry;
//console.log('daliactor', daliactor.id, 'shader', shader.dalishader.id, 'geometry', daligeometry.id);
// set uniforms
//shader.addUniforms(shader.dreem_shader);
SET_UNIFORMS
// textures
TEXTURE_START
var texture = TEXTURE_VALUE
// lets fetch the sampler
var gltex = texture.TEXTURE_SAMPLER
// lets do the texture slots correct
if(!gltex){
if(!texture.createGLTexture) texture = TEXTURE_VALUE = root.Texture.fromStub(texture)
gltex = texture.createGLTexture(gl, TEXTURE_ID, TEXTURE_INFO)
if (texture.image) {
var ti = TEXTURE_INFO
//TODO Get current values for sampler
var sampler = new dali.Sampler();
sampler.setFilterMode(dali.FILTER_MODE_LINEAR, dali.FILTER_MODE_LINEAR);
sampler.setWrapMode(dali.WRAP_MODE_CLAMP_TO_EDGE, dali.WRAP_MODE_CLAMP_TO_EDGE);
if (DaliApi.emitcode) {
console.log('DALICODE: var sampler' + dalimaterial.id + ' = new dali.Sampler();');
console.log('DALICODE: sampler' + dalimaterial.id + '.setFilterMode(dali.FILTER_MODE_LINEAR, dali.FILTER_MODE_LINEAR);');
console.log('DALICODE: sampler' + dalimaterial.id + '.setWrapMode(dali.WRAP_MODE_CLAMP_TO_EDGE, dali.WRAP_MODE_CLAMP_TO_EDGE);');
}
//FIX
if (dalimaterial) {
var index = dalimaterial.addTexture(texture, ti.loc, sampler);
gltex.texture_index = index;
//console.log('**** **** **** dali.addTexture', ti.loc, texture.image.getWidth(), texture.image.getHeight(), 'return index', index);
}
}
if(!gltex) return 0
}
else{
gl.activeTexture(TEXTUREGL_ID) // gl.TEXTURE0 + TEXTURE_ID
gl.bindTexture(gl.TEXTURE_2D, gltex)
if (texture.image) {
var sampler = new dali.Sampler();
sampler.setFilterMode(dali.FILTER_MODE_LINEAR, dali.FILTER_MODE_LINEAR);
sampler.setWrapMode(dali.WRAP_MODE_CLAMP_TO_EDGE, dali.WRAP_MODE_CLAMP_TO_EDGE);
if (DaliApi.emitcode) {
console.log('DALICODE: var sampler' + dalimaterial.id + ' = new dali.Sampler();');
console.log('DALICODE: sampler' + dalimaterial.id + '.setFilterMode(dali.FILTER_MODE_LINEAR, dali.FILTER_MODE_LINEAR);');
console.log('DALICODE: sampler' + dalimaterial.id + '.setWrapMode(dali.WRAP_MODE_CLAMP_TO_EDGE, dali.WRAP_MODE_CLAMP_TO_EDGE);');
}
var ti = TEXTURE_INFO
var index = dalimaterial.addTexture(texture, ti.loc, sampler);
}
if(texture.updateid !== gltex.updateid){
texture.updateGLTexture(gl, gltex)
if (gltex.texture_index) {
var dalimaterial = root.dalimaterial;
dalimaterial.removeTexture(gltex.texture_index);
gltex.texture_index = undefined;
if (texture.image) {
var ti = TEXTURE_INFO
//TODO Get current values for sampler
var sampler = new dali.Sampler();
sampler.setFilterMode(dali.FILTER_MODE_LINEAR, dali.FILTER_MODE_LINEAR);
sampler.setWrapMode(dali.WRAP_MODE_CLAMP_TO_EDGE, dali.WRAP_MODE_CLAMP_TO_EDGE);
if (DaliApi.emitcode) {
console.log('DALICODE: var sampler = new dali.Sampler();');
console.log('DALICODE: sampler.setFilterMode(dali.FILTER_MODE_LINEAR, dali.FILTER_MODE_LINEAR);');
console.log('DALICODE: sampler.setWrapMode(dali.WRAP_MODE_CLAMP_TO_EDGE, dali.WRAP_MODE_CLAMP_TO_EDGE);');
}
var index = dalimaterial.addTexture(texture.image, ti.loc, sampler);
gltex.texture_index = index;
}
}
}
}
gl.uniform1i(TEXTURE_LOC, TEXTURE_ID)
if(TEXTURE_ID > 0)debugger
TEXTURE_END
// attributes
//shader.compileShader(this);
//console.log('---- ---- ---- addAttributeGeometry');
//shader.daligeometry.addAttributeGeometry(shader, shader.attrlocs);
var len = 0 // pull the length out of the buffers
var lastbuf
ATTRLOC_START
var buf = ATTRLOC_BUF
if(lastbuf !== buf){
lastbuf = buf
if(!buf.glvb) buf.glvb = gl.createBuffer()
if(buf.length > len) len = buf.length
gl.bindBuffer(gl.ARRAY_BUFFER, buf.glvb)
if(!buf.clean){
gl.bufferData(gl.ARRAY_BUFFER, buf.array, gl.STATIC_DRAW)
buf.clean = true
}
}
var loc = ATTRLOC_LOC
gl.enableVertexAttribArray(loc)
ATTRLOC_ATTRIBPTR
ATTRLOC_END
var blender = root.dalimaterial.hasBlender() ? root.dalimaterial : root.dalirenderer;
// set up blend mode
if(root.alpha_blend_eq.op){
//console.log('==== alpha_blend_eq.op');
var constant = root.constant
if(constant) {
//console.log('CONSTANT', constant[0], constant[1], constant[2], constant[3], 'Not implemented');
gl.blendColor(constant[0], constant[1], constant[2], constant.length>3? constant[3]: 1)
}
gl.enable(gl.BLEND)
gl.blendEquationSeparate(root.color_blend_eq.op, root.alpha_blend_eq.op)
gl.blendFuncSeparate(
root.color_blend_eq.src,
root.color_blend_eq.dst,
root.alpha_blend_eq.src,
root.alpha_blend_eq.dst
)
// DALI
//console.log('*** full blend');
blender.setBlendMode(dali.BLENDING_ON);
blender.setBlendEquation (root.color_blend_eq.op, root.color_blend_eq.op);
blender.setBlendFunc(root.color_blend_eq.src, root.color_blend_eq.dst, root.alpha_blend_eq.src, root.alpha_blend_eq.dst);
}
else if(root.color_blend_eq.op){
//console.log('BLEND', root.color_blend_eq);
var constant = root.constant
if (constant) {
//console.log('CONSTANT 2', constant[0], constant[1], constant[2], constant[3], 'Not implemented');
gl.blendColor(constant[0], constant[1], constant[2], constant.length>3? constant[3]: 1)
}
gl.enable(gl.BLEND)
gl.blendEquation(root.color_blend_eq.op)
gl.blendFunc(root.color_blend_eq.src, root.color_blend_eq.dst)
blender.setBlendMode(dali.BLENDING_ON);
blender.setBlendEquation (root.color_blend_eq.op, root.color_blend_eq.op);
//TODO Check this. What are the last two args?
blender.setBlendFunc(root.color_blend_eq.src, root.color_blend_eq.dst, root.color_blend_eq.src, root.color_blend_eq.dst);
//dalimaterial.setBlendFunc(dali.BLEND_FACTOR_SRC_COLOR, dali.BLEND_FACTOR_DST_COLOR, root.color_blend_eq.src, root.color_blend_eq.dst);
//dalimaterial.setBlendFunc(root.color_blend_eq.src, root.color_blend_eq.dst, dali.BLEND_FACTOR_ONE, dali.BLEND_FACTOR_ZERO);
//dalimaterial.setBlendFunc(root.color_blend_eq.src, root.color_blend_eq.dst, dali.BLEND_FACTOR_SRC_ALPHA, dali.BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
//dalimaterial.setBlendFunc(root.color_blend_eq.src, root.color_blend_eq.dst, dali.BLEND_FACTOR_CONSTANT_ALPHA, dali.BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA);
}
else{
//console.log('==== blend disabled');
gl.disable(gl.BLEND)
//DALI
blender.setBlendMode(dali.BLENDING_OFF);
}
// set up depth test
if(root.depth_test_eq.func){
console.log('***Depth test enabled. NOT IMPLEMENTED');
gl.enable(gl.DEPTH_TEST)
gl.depthFunc(root.depth_test_eq.func)
}
else{
gl.disable(gl.DEPTH_TEST)
}
return len
}
// {object} shader DaliShader object, amended with location information
// (see getLocations call above)
// The 'this' pointer is a view
this.compileUse = function(shader){
// Make sure the object has dali
//DaliApi.createDaliObjects(this.shader);
//console.log('*****compileUse', shader.object_type, this.object_type);
// alright lets compile our useShader from
var tpl = this.useShaderTemplate.toString()
tpl = tpl.replace(/^function/, "function useshader_" + (this.view?this.view.constructor.name:'anonymous') + '_shader_' + this.constructor.name)
// ok lets replace shit.
// set uniforms
var uniset = shader.uniset
var unilocs = shader.unilocs
var refattr = shader.refattr
var out = 'var loc, uni\n'
out += 'var actor = root.daliactor\n'
out += 'if (shader && actor) {\n'
for(var key in uniset){
var loc = unilocs[key]
var split = loc.split
var isattr = key in refattr
if(split){
var name = ''
for(var i = 0; i < split.length; i++){
if(i) name += '.'
var part = split[i]
if(part === 'layout' || isattr && i === split.length - 1) name += '_'
name += part
}
out += '\t\tuni = root.' + name + '\n'
}
else{
out += '\t\tuni = root.'
if(isattr) out += '_'
out += key + '\n'
}
out += '\t\tloc = shader.unilocs.' + key + '\n'
var gen = gltypes.uniform_gen[loc.type]
//if(gen.args == 1){
var call = gen.call
//if(call !== 'uniformMatrix4fv' && call !== 'uniformMatrix3fv' && call !== 'uniformMatrix2fv'){
// out += '\t\tif(loc.value !== uni) loc.value = uni, '
//}
// Update uniform. Use registerAnimatableProperty only if
// the value is not set yet. (DALI)
//TODO Optimize
//out += 'console.log(\'------ROOT\', root.view.id, root.daliactor.object_type)\n'
out += '\t\tvar val = actor.setUniformValue(\'' + key + '\',uni)\n'
// Use addUniformValue instead of this code
/*
out += '\t\tvar val = shader.getArrayValue(uni)\n'
out += '\t\tvar v = shader.meshActor._' + key + '\n'
out += '\tconsole.log(\'key\',\'' + key + '\',\'value\', val)\n'
out += '\t\tif (v) {v = val} \n'
out += '\t\telse {shader.meshActor.registerAnimatableProperty(\'_' + key + '\', val)}\n'
*/
/*
out += 'gl.' + gen.call + '(loc.loc'
if(gen.mat) out += ', false'
if(gen.args == 1) out += ',uni)\n'
if(gen.args == 2) out += ',uni[0], uni[1])\n'
if(gen.args == 3) out += ',uni[0], uni[1], uni[2])\n'
if(gen.args == 4) out += ',uni[0], uni[1], uni[2], uni[3])\n'
if(gen.args === this.loguni) out += 'if(typeof uni === "number")console.log(uni)\n'
*/
}
out += '}\n'
tpl = tpl.replace(/SET\_UNIFORMS/, out)
tpl = tpl.replace(/TEXTURE\_START([\S\s]*)TEXTURE\_END/, function(m){
var out =''
var body = m.slice(13,-11)
var texlocs = shader.texlocs
var texid = 0
for(var key in texlocs){
var texinfo = texlocs[key]
var split = texinfo.split
var TEXTURE_VALUE =''
if(split){
TEXTURE_VALUE = 'root.' + split.join('.')
}
else{
TEXTURE_VALUE = 'root.' + texinfo.name
}
//console.log('key', key);
//console.log('TEXTURE_VALUE', TEXTURE_VALUE);
//console.log('TEXTURE_SAMPLER', texinfo.samplerid);
//console.log('TEXTURE_ID', texid);
//console.log('TEXTURE_LOC', 'shader.texlocs.' + key+ '.loc');
//console.log('TEXTURE_INFO', 'shader.texlocs.' + key);
//console.log('TEXTUREGL_ID', gltypes.gl.TEXTURE0 + texid);
out += body
.replace(/TEXTURE_VALUE/g, TEXTURE_VALUE)
.replace(/TEXTURE_SAMPLER/g, texinfo.samplerid)
.replace(/TEXTURE_ID/g, texid)
.replace(/TEXTURE_LOC/g, 'shader.texlocs.' + key+ '.loc')
.replace(/TEXTURE_INFO/g, 'shader.texlocs.' + key)
.replace(/TEXTUREGL_ID/g, gltypes.gl.TEXTURE0 + texid)
}
//console.log('=-=-=-=-=- texlocs', out);
return out
})
tpl = tpl.replace(/ATTRLOC\_START([\S\s]*)ATTRLOC\_END/, function(m){
var body = m.slice(13,-11)
var out = ''
var attrlocs = shader.attrlocs
var len = 0 // pull the length out of the buffers
var lastbuf
if (Object.keys(attrlocs).length > 0) {
//console.log('*************************** attrlocs ***********************');
//console.log(attrlocs);
//console.log('************************************************************');
out += 'root.daligeometry.addAttributeGeometry(root, shader.attrlocs)\n'
}
for(var key in attrlocs){
var attrloc = attrlocs[key]
var ATTRLOC_BUF
if(attrloc.name){
ATTRLOC_BUF = 'root.' + attrloc.name
var buf = this[attrloc.name]
}
else{
ATTRLOC_BUF = 'root.' + key
}
var ATTRLOC_LOC = 'shader.attrlocs.' + key +'.loc'
if(attrloc.name){
ATTRLOC_ATTRIBPTR =
'gl.vertexAttribPointer(loc, '+attrloc.slots+', gl.FLOAT, false, buf.stride, '+attrloc.offset+')'
//ATTRLOC_ATTRIBPTR = 'console.log(\'buf type 1\', \'' + key + '\',' + attrloc.slots + ', buf.stride, buf.length,' + attrloc.offset + ');daligeometry.addVertices(\'' + key + '\', buf.array, ' + attrloc.slots + ', buf.stride, ' + attrloc.offset + ')'
}
else{
ATTRLOC_ATTRIBPTR =
'if(buf.slots>4)debugger;gl.vertexAttribPointer(loc, buf.slots, gl.FLOAT, false, buf.stride, 0)'
//ATTRLOC_ATTRIBPTR = 'console.log(\'buf type 2\', \'' + key + '\',buf.slots, buf.stride, buf.length);daligeometry.addVertices(\'' + key + '\', buf.array, buf.slots, buf.stride, 0)'
}
//HACK. Setting this for text causes problems with image display
ATTRLOC_ATTRIBPTR = ''
out += body
.replace(/ATTRLOC_BUF/, ATTRLOC_BUF)
.replace(/ATTRLOC_LOC/, ATTRLOC_LOC)
.replace(/ATTRLOC_ATTRIBPTR/, ATTRLOC_ATTRIBPTR)
}
return out
})
tpl = tpl.replace(/gl.[A-Z][A-Z0-9_]+/g, function(m){
return gltypes.gl[m.slice(3)]
})
//if (shader.texlocs && shader.texlocs.length > 0)
//console.log('FUNCTION', this.view.id, tpl);
//console.log('FUNCTION', tpl);
//shader.use = new Function('return ' + tpl)().bind(this);
shader.use = new Function('return ' + tpl)();
}
// all draw types
exports.TRIANGLES = this.TRIANGLES = 0x4
exports.LINES = this.LINES = 0x1
exports.LINE_LOOP = this.LINE_LOOP = 0x2
exports.LINE_STRIP = this.LINE_STRIP = 0x3
exports.TRIANGLE_STRIP = this.TRIANGLE_STRIP = 0x5
exports.TRIANGLE_FAN = this.TRIANGLE_FAN = 0x6
this.drawtype = this.TRIANGLES
// lets draw ourselves.
// A view (the this pointer) makes one call to drawArrays for each shader.
// A typical number is two (one for border and one for hardimage
this.drawArrays = function(devicegl, sub, start, end){
//if (this.texture) {
// console.trace('drawArrays');
//}
//console.trace('*****drawArrays', (this.view? this.view.id : '<screen>'));
// console.log('PROG', this.vtx_state.code);
//if(this.mydbg) debugger
if(!this.hasOwnProperty('shader') || this.shader === undefined) this.compile(devicegl)
var gl = devicegl.gl
var shader = sub? this.shader[sub]: this.shader;
// Attach the dali_obj to the shader.shader object (DALI)
var len = this.useShader(gl, shader);
if(len) gl.drawArrays(this.drawtype, start || 0, end === undefined?len: end)
}
})