UNPKG

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

435 lines (374 loc) 13.6 kB
/* 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, baseclass){ // internal, drawing var Shader = require('./shaderheadless') /** * @method DrawPass constructor * @param {Object} gldevice Instance of DeviceHeadless * @param {Object} view Instance of View */ this.atConstructor = function(gldevice, view){ this.device = gldevice this.view = view view.drawpass = this // lets do the flatten this.pickmatrices = { viewmatrix: mat4.identity(), noscrollmatrix: mat4.identity() } this.colormatrices = { viewmatrix: mat4.identity(), noscrollmatrix: mat4.identity() } this.debugrect = new DebugRect() } this.atDestroy = function(){ this.releaseTexture() } this.poolDrawTargets = function(){ var pools = this.device.drawtarget_pools if(!this.drawtargets) return for(var i = 0; i < this.drawtargets.length; i ++){ var dt = this.drawtargets[i] if(!pools[dt]) pools[dt] = [] pools[dt].push(this[dt]) this[dt] = null } } this.allocDrawTarget = function(width, height, view, drawtarget, passid){ //console.log('allocDrawTarget', width, height, drawtarget, passid); width = floor(width) height = floor(height) var Texture = this.device.Texture if(!this.drawtargets) this.drawtargets = [] if(this.drawtargets.indexOf(drawtarget) === -1) this.drawtargets.push(drawtarget) var dt = this[drawtarget] //var twidth = this.nextPowerTwo(layout.width* main_ratio), theight = this.nextPowerTwo(layout.height* main_ratio) if(!dt){ // lets scan the pools for a suitable drawtarget, otherwise create it var pool = this.device.drawtarget_pools[drawtarget] if(pool && pool.length){ // first find a drawtarget with the same size for(var i = 0; i < pool.length; i ++){ var tgt = pool[i] if(!tgt) continue var size = tgt.size if(size[0] === width && size[1] === height){ // lets remove it from the pool pool.splice(i,1) dt = tgt break } } // then we find a drawtarget with the same passid as last time if(!dt){ for(var i = 0; i < pool.length; i++){ var tgt = pool[i] if(!tgt) continue if(passid === tgt.passid){ dt = tgt pool.splice(i,1) break } } } } // otherwise we create a new one if(!dt){ dt = this[drawtarget] = Texture.createRenderTarget(view._viewport === '2d'?Texture.RGB:Texture.RGBA|Texture.DEPTH|Texture.STENCIL, width, height, this.device) } else this[drawtarget] = dt dt.passid = passid } // make sure the drawtarget has the right size var tsize = this[drawtarget].size if(width !== tsize[0] || height !== tsize[1]){ this[drawtarget].delete() this[drawtarget] = Texture.createRenderTarget(view._viewport === '2d'?Texture.RGB:Texture.RGBA|Texture.DEPTH|Texture.STENCIL, width, height, this.device) } } this.calculateDrawMatrices = function(isroot, storage, mousex, mousey){ var view = this.view var scroll = view._scroll var layout = view._layout if(view._viewport === '2d'){ if(isroot && mousex !== undefined){ var sizel = 0 var sizer = 1 mat4.ortho(scroll[0] + mousex - sizel, scroll[0] + mousex + sizer, scroll[1] + mousey - sizer, scroll[1] + mousey + sizel, -100, 100, storage.viewmatrix) mat4.ortho( mousex - sizel, mousex + sizer, mousey - sizer, mousey + sizel, -100, 100, storage.noscrollmatrix) } else{ var zoom = view._zoom if (isroot){ mat4.ortho(scroll[0], layout.width*zoom+scroll[0], scroll[1], layout.height*zoom+scroll[1], -100, 100, storage.viewmatrix) mat4.ortho(0, layout.width, 0, layout.height, -100, 100, storage.noscrollmatrix) } else{ mat4.ortho(scroll[0], layout.width*zoom+scroll[0], layout.height*zoom+scroll[1], scroll[1], -100, 100, storage.viewmatrix) mat4.ortho(0, layout.width, layout.height, 0, -100, 100, storage.noscrollmatrix) } } } else if(view._viewport === '3d'){ storage.perspectivematrix = mat4.perspective(view._fov * PI * 2/360.0 , layout.width/layout.height, view._nearplane, view._farplane) storage.lookatmatrix = mat4.lookAt(view._camera, view._lookat, view._up) storage.viewmatrix = mat4.mat4_mul_mat4(storage.lookatmatrix,storage.perspectivematrix); } } function isInBounds2D(view, draw){ if(draw.noboundscheck) return true var height = view._layout.height var width = view._layout.width var drawlayout = draw._layout if(draw.parent && draw.parent !== view){ drawlayout.absx = draw.parent._layout.absx + drawlayout.left drawlayout.absy = draw.parent._layout.absy + drawlayout.top } else{ drawlayout.absx = drawlayout.left drawlayout.absy = drawlayout.top } // if(draw === view && view.sublayout){ // width = view.sublayout.width // height = view.sublayout.height // } // early out check // if(draw !== view && !draw.noscroll){ // var scroll = view._scroll // var zoom = view._zoom // if( drawlayout.absy - scroll[1] > height * zoom || drawlayout.absy + drawlayout.height - scroll[1] < 0){ // return false // } // if(drawlayout.absx - scroll[0] > width * zoom || drawlayout.absx + drawlayout.width - scroll[0] < 0){ // return false // } // } return true } this.nextItem = function(draw){ var view = this.view var next = (draw === view || (!draw._viewport && draw._visible)) && draw.children[0], next_index = 0 while(!next){ // skip to parent next if(draw === view) break next_index = draw.draw_index + 1 draw = draw.parent next = draw.children[next_index] } if(next === view) return undefined if(next) next.draw_index = next_index return next } this.drawPick = function(isroot, passid, mousex, mousey, debug){ var view = this.view var device = this.device var layout = view._layout var gl = device.gl if(!layout || layout.width === 0 || isNaN(layout.width) || layout.height === 0 || isNaN(layout.height)) return if(isroot){ if(!debug) this.allocDrawTarget(1, 1, this.view, 'pick_buffer', passid) } else{ var ratio = view._pixelratio if(isNaN(ratio)) ratio = device.main_frame.ratio ratio = 1 var twidth = layout.width * ratio, theight = layout.height * ratio this.allocDrawTarget(twidth, theight, this.view, 'pick_buffer', passid) } gl.disable(gl.SCISSOR_TEST) device.bindFramebuffer(this.pick_buffer || null) device.clear(0,0,0,0) var matrices = this.pickmatrices this.calculateDrawMatrices(isroot, matrices, debug?undefined:mousex, mousey) // calculate the colormatrices too //if(!this.colormatrices.initialized){ // this.calculateDrawMatrices(isroot, this.colormatrices) //} var pickguid = vec3() pickguid[0] = passid/255//(((passid)*131)%256)/255 // modulo inverse: http://www.wolframalpha.com/input/?i=multiplicative+inverse+of+31+mod+256 var pick_id = 0 var draw = view while(draw){ draw.draw_dirty &= 1 pick_id+= draw.pickrange; if(!draw._visible || draw._first_draw_pick && view._viewport === '2d' && draw.boundscheck && !isInBounds2D(view, draw)){ // do early out check using bounding boxes } else{ draw._first_draw_pick = 1 var id = pick_id//(pick_id*29401)%65536 pickguid[1] = (id&255)/255 pickguid[2] = (id>>8)/255 draw.pickguid = pickguid[0]*255<<16 | pickguid[1]*255 << 8 | pickguid[2]*255 draw.viewmatrix = matrices.viewmatrix if(!draw._visible) continue if(draw._viewport && draw.drawpass !== this && draw.drawpass.pick_buffer){ // ok so the pick pass needs the alpha from the color buffer // and then hard forward the color var blendshader = draw.shaders.viewportblend if (view._viewport === '3d'){ // dont do this! blendshader.depth_test = 'src_depth <= dst_depth' } else{ blendshader.depth_test = '' } blendshader.texture = draw.drawpass.pick_buffer blendshader._width = draw.layout.width blendshader._height = draw.layout.height blendshader.drawArrays(this.device) } else{ //draw.updateShaders() // alright lets iterate the shaders and call em var shaders = draw.shader_draw_list for(var j = 0; j < shaders.length; j++){ var shader = shaders[j] shader.pickguid = pickguid if(!shader.visible) continue if(draw.pickalpha !== undefined)shader.pickalpha = draw.pickalpha if(shader.noscroll) draw.viewmatrix = matrices.noscrollmatrix else draw.viewmatrix = matrices.viewmatrix shader.drawArrays(this.device, 'pick') } } } draw = this.nextItem(draw) } } this.getDrawID = function(id){ var view = this.view var draw = view var pick_id = 0 while(draw){ if(id > pick_id && id <= pick_id + draw.pickrange){ draw.last_pick_id = (pick_id + draw.pickrange) - id return draw } pick_id += draw.pickrange draw = this.nextItem(draw) } } this.drawBlend = function(draw){ if(!draw.drawpass.color_buffer){ console.error("Null color_buffer detected") } else { // ok so when we are drawing a pick pass, we just need to 1 on 1 forward the color data // lets render the view as a layer var blendshader = draw.shaders.viewportblend if (this.view._viewport === '3d'){ blendshader.depth_test = 'src_depth <= dst_depth' } else{ blendshader.depth_test = '' } blendshader.texture = draw.drawpass.color_buffer blendshader.width = draw._layout.width blendshader.height = draw._layout.height blendshader.drawArrays(this.device) } } this.drawNormal = function(draw, matrices){ draw.updateShaders() var count = 0 // alright lets iterate the shaders and call em var shaders = draw.shader_draw_list for(var j = 0; j < shaders.length; j++){ // lets draw em var shader = shaders[j] if(shader.pickonly || !shader.visible) continue // was pick only // we have to set our guid. if(shader.noscroll) draw.viewmatrix = matrices.noscrollmatrix else draw.viewmatrix = matrices.viewmatrix count++ shader.drawArrays(this.device) } return count } this.drawColor = function(isroot, time, clipview){ var view = this.view var device = this.device var layout = view._layout var gl = device.gl var count = 0 if(!layout || layout.width === 0 || isNaN(layout.width) || layout.height === 0 || isNaN(layout.height)) return // lets see if we need to allocate our framebuffer.. if(!isroot){ var ratio = view._pixelratio if(isNaN(ratio)) ratio = device.main_frame.ratio var twidth = layout.width * ratio, theight = layout.height * ratio this.allocDrawTarget(twidth, theight, this.view, 'color_buffer') } this.device.bindFramebuffer(this.color_buffer || null) if(layout.width === 0 || layout.height === 0) return false device.clear(view._clearcolor) var hastime = false var zoom = view._zoom var matrices = this.colormatrices this.calculateDrawMatrices(isroot, matrices); view.colormatrices = matrices gl.disable(gl.SCISSOR_TEST) if(isroot){ /* if(clipview){ var ratio = this.device.frame.ratio var xs = this.device.frame.size[0] / ratio var ys = this.device.frame.size[1] / ratio var clayout = clipview._layout var c1 = vec2.mul_mat4(vec2(0, 0),clipview.viewportmatrix) var c2 = vec2.mul_mat4(vec2(clayout.width, clayout.height),clipview.viewportmatrix) var x1 = c1[0], y1 = c1[1], x2 = c2[0] - x1, y2 = c2[1] - y1 gl.enable(gl.SCISSOR_TEST) gl.scissor((x1)*ratio, (ys - y2 - y1)*ratio, x2 * ratio, (y2)*ratio)//x1*2, y1*2, x2*2, y2*2) } */ } device.clear(view._clearcolor) var draw = view while(draw){ draw.draw_dirty &= 2 //} //for(var dl = this.draw_list, i = 0; i < dl.length; i++){ // var draw = dl[i] if(!draw._visible || draw._first_draw_color && view._viewport === '2d' && draw.boundscheck && !isInBounds2D(view, draw)){ // do early out check using bounding boxes } else{ draw._first_draw_color = 1 //if(view.constructor.name === 'slideviewer')console.log('here',draw.constructor.name, draw.text) draw._time = time if(draw._listen_time || draw.ontime) hastime = true draw.viewmatrix = matrices.viewmatrix if(draw.atDraw) draw.atDraw(this) if(draw._viewport && draw.drawpass !== this){ this.drawBlend(draw) } else{ count += this.drawNormal(draw, matrices) } if(draw.debug_view){ this.debugrect.view = draw this.debugrect.drawArrays(this.device) } } draw = this.nextItem(draw) } //console.log(count) return hastime } var DebugRect = define.class(Shader, function(){ this.view = {totalmatrix:mat4(), viewmatrix:mat4(), layout:{width:0, height:0}} this.mesh = vec2.array() this.mesh.pushQuad(0,0,1,0,0,1,1,1) this.position = function(){ return vec4(vec2(mesh.x * view.layout.width, mesh.y * view.layout.height), 0, 1) * view.totalmatrix * view.viewmatrix } this.color = function(){ return vec4(1,0,0,0.5) } }) })