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

659 lines (554 loc) 22.3 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, $ui$, view, label, scrollbar, textbox, numberbox){ var Shader = this.Shader = require('$system/platform/$platform/shader$platform') this.attributes = { // the value of the colorpicker, a color value: Config({type: vec4, value: "white", meta:"color", rerender:false}), // the foreground color of the fonts fontsize: Config({type: int, value: 14, meta:"fontsize"}), // internal border color internalbordercolor: Config({type:vec4, value:vec4(1,1,1,0.6), meta:"color"}), // read-only the hue value (HSV) basehue: Config({type:float, value:0.5, readonly:true, rerender:false}), // read-only the saturation value (HSV) basesat: Config({type:float, value:0.8, readonly:true, rerender:false}), // read-only, the value (HSV) baseval: Config({type:float, value:0.5, readonly:true, rerender:false}), sliderheight: Config({type: float, value:15}), colorwheel:Config({type:Boolean, value:true}), colorsliders:Config({type:Boolean, value:true}), colorbox:Config({type:Boolean, value:true}) } this.basehue = 0.5 this.bgcolor = vec4(0.0, 0.0, 0.0, 0.4) this.flexdirection = "column" this.padding = vec4(10) this.minwidth = 200 this.maxwidth = 300 this.borderradius = 3 this.borderwidth = 1 this.bordercolor = this.internalbordercolor this.contrastcolor = vec4("black") this.internalbordercolor= function(){ this.bordercolor = this.internalbordercolor } this.updatecontrol = function(name, val){ var c = this.findChild(name); if (c){ c.currentcolor = this.value; c.contrastcolor = this.contrastcolor; c.basehue = this.basehue; c.basesat = this.basesat; c.baseval = this.baseval; newoff = val * (255); if (newoff < 0) newoff += 256; c._offset = newoff } } this.updatelabel = function(name, val){ var c = this.findChild(name); if (c) c.value = val; //else console.log("not found", name); } this.numbertohex = function(num){ if (num < 16){ return "0"+ (Math.round(num).toString(16)); } return Math.round(num).toString(16); } this.buildhexnumber = function(vector){ return "" + this.numbertohex(vector[0]*255) + this.numbertohex(vector[1]*255) + this.numbertohex(vector[2]*255); } this.updateallcontrols = function(){ this.updatecontrol("hsvider", this.basehue); this.updatecontrol("sslider", this.basesat); this.updatecontrol("lslider", this.baseval); this.updatecontrol("rslider", this.value[0]); this.updatecontrol("gslider", this.value[1]); this.updatecontrol("bslider", this.value[2]); this.updatecontrol("squareview", this.basehue); this.updatecontrol("colorcirclecontrol", this.basehue); this.updatelabel("texth", Math.round(this.basehue * 360)); this.updatelabel("texts", Math.round(this.basesat * 100)); this.updatelabel("textv", Math.round(this.baseval * 100)); this.updatelabel("textr", Math.round(this.value[0] * 255)); this.updatelabel("textg", Math.round(this.value[1] * 255)); this.updatelabel("textb", Math.round(this.value[2] * 255)); this.updatelabel("texta", Math.round(this.value[3] * 255)); var t = this.buildhexnumber(this.value); this.updatelabel("hexcolor", t); } this.value = function(){ this.createHSVFromColor(); this.contrastcolor = vec4.fromHSV(0, 0, 1 - this.baseval * (1 - this.basesat*0.5),1) this.updateallcontrols(); } this.createColorFromHSV = function(){ this._value = vec4.fromHSV(this.basehue, this.basesat, this.baseval); if (this.valuechange) this.valuechange(this._value, this._value, this); } this.createHSVFromColor = function(){ var res = vec4.toHSV(this.value); this.basehue = res[0]; this.basesat = res[1]; this.baseval = res[2]; } this.setRed = function(r){ this.value[0] = r; this.createHSVFromColor(); this.updateallcontrols(); } this.setGreen = function(g){ this.value[1] = g; this.createHSVFromColor(); this.updateallcontrols(); } this.setBlue = function(b){ this.value[2] = b; this.createHSVFromColor(); this.updateallcontrols(); } this.setHueBase = function(h){ this.basehue = h; this.createColorFromHSV(); this.updateallcontrols(); } this.setSatBase = function(s){ this.basesat = s; this.createColorFromHSV(); this.updateallcontrols(); } this.setLumBase = function(s){ this.baseval = s; this.createColorFromHSV(); this.updateallcontrols(); } define.class(this, "customslider", function($ui$,view){ this.attributes = { // hsv color for the left side hsvfrom:Config({type:vec3, value: vec3(0,1,0.5)}), // hsv color for the right side hsvto:Config({type:vec3, value: vec3(1,1,0.5)}), hsvhueadd:Config({type:float, value:0}), basehue:Config({type:float, value: 0}), currentcolor: Config({type:vec4, value: vec4("red")}), contrastcolor: Config({type:vec4, value: vec4("white")}), // Color of the draggable part of the scrollbar draggercolor: Config({type: vec4, value: vec4(1,1,1,0.8)}), // Color of the draggable part of the scrollbar draggerradius: Config({type: float, value: 3}), // Color when the pointer is hovering over the draggable part of the scrollbar hovercolor: Config({type: vec4, value: vec4("#8080c0")}), // Color of the draggable part of the scrollbar while actively scrolling activecolor: Config({type: vec4, value: vec4("#8080c0")}), // Is this a horizontal or a vertical scrollbar? vertical: Config({type: Boolean, value: false}), // Current start offset of the scrollbar. Ranges from 0 to total - page offset: Config({type:float, value:0}), // Page size, in total page: Config({type:float, value:25}), // total size. total: Config({type:float, value:255+25}), // set animation on bgcolor bgcolor: Config({duration: 1.0}) } var scrollbar = this.constructor; this.page = function(){ this.redraw() } this.offset = function(){ this.redraw() } var mesh = vec2.array() mesh.pushQuad(0,0,0,1,1,0,1,1) this.borderwidth = 0 this.margin = 1 this.bordercolor = vec4("#303060") this.pressed = 0 this.hovered = 0 this.hardrect = { offset: 0, page: 0.3, color: function(){ // we have a rectangle var hsvamix = vec4(mix(view.hsvfrom, view.hsvto, mesh.x), 1.0) hsvamix.r += view.hsvhueadd * view.basehue; var bg = colorlib.hsva(hsvamix); var rel = vec2(mesh.x*view.layout.width, mesh.y*view.layout.height) var offset = view.offset / view.total var page = view.page / view.total var edge = 0.1//min(length(vec2(length(dFdx(rel)), length(dFdy(rel)))) * SQRT_1_2, 0.001) var field = float(0) if(view.vertical){ field = shape.roundbox(rel, 0.00 * view.layout.width, offset*view.layout.height,.9*view.layout.width, page*view.layout.height, view.draggerradius) } else{ field = shape.roundbox(rel, offset * view.layout.width, 0.00*view.layout.height,page*view.layout.width, 1.0*view.layout.height, view.draggerradius) } var fg = vec4(view.contrastcolor.rgb, smoothstep(-edge, edge, 1-abs(-field-1.))*view.contrastcolor.a) var fg2 = vec4(view.currentcolor.rgb, smoothstep(0.,-edge, field)*view.currentcolor.a) //return vec4(vec3(sin(field*0.1))+ fg2.a*vec3(1,0,0) + fg.a*vec3(0,1,0), 1.) return mix(bg.rgba, mix(fg2.rgba, fg.rgba, fg.a), max(fg.a,fg2.a)) }, mesh: mesh, update:function(){}, position: function(){ return vec4(mesh.x * view.layout.width, mesh.y * view.layout.height, 0, 1) * view.totalmatrix * view.viewmatrix } } this.hardrect = true // this.bg = true; // TODO(aki): fix slider and use pointer events // most of the logic below is unnecessary because pointer events include deltas. // this.pointerstart = function(event){ // var start = this.globalToLocal(event.position) // // detect if we clicked not on the button // if(this.vertical){ // var p = start[1] / this.layout.height // } // else{ // var p = start[0] / this.layout.width // } // var offset = this.offset / this.total // var page = this.page / this.total // var start_offset = 0; // if(p < offset){ // var value = clamp(p - 0.5 * page, 0, 1.-page) * this.total // if(value != this.offset){ // this.offset = value // } // } // else if (p > offset + page){ // var value = clamp(p - 0.5*page, 0, 1.-page) * this.total // if(value != this.offset){ // this.offset = value // } // } // start_offset = offset//this.offset / this.total // } // this.pointermove = function(event){ // var pos = this.globalToLocal(event.position) // if(this.vertical){ // var p = start_offset + (pos[1] - start[1]) / this.layout.height // } // else{ // var p = start_offset + (pos[0] - start[0]) / this.layout.width // } // var value = clamp(p, 0, 1.-page) * this.total // if(value != this.offset){ // this.offset = value // } // } //this.height = 10; //this.width = 100; //this.flex = 1; this.drawcount = 0; }) define.class(this, 'colorcirclecontrol', function($ui$view){ this.name = 'colorcirclecontrol' this.width = 200; this.height = 200; this.bgcolor = NaN this.attributes = { ringwidth: Config({type:float, value: 0.3}), hover: Config({type:float, value: 0, motion:"linear", duration: 0.2}), basehue: Config({type:float, value:0.7}), basesat: Config({type:float, value:0.7}), baseval: Config({type:float, value:0.7}), currentcolor: Config({type:vec4, value:"white"}), contrastcolor: Config({type:vec4, value: vec4("white")}), draggersize: Config({type:float, value: 8}), } this.updatehue = function(pos){ var dx = pos[0] - this.layout.width/2; var dy = pos[1] - this.layout.height/2; dx /= this.layout.width/2; dy /= this.layout.height/2; var angle = Math.atan2(dy,dx); this.outer.setHueBase(-angle/ 6.283+ 0.25); } this.pointerend = this.pointermove = function(event){ var a = this.globalToLocal(event.position) this.updatehue(a); this.redraw(); } define.class(this, 'bgfill', this.Shader, function(){ this.draworder = 1; this.vertexstruct = define.struct({ p:float, side: float }) this.mesh = this.vertexstruct.array(); this.drawtype = this.TRIANGLE_STRIP this.position = function(){ uv = vec2(sin(mesh.p), cos(mesh.p))*(1-view.ringwidth + view.ringwidth*mesh.side); off = mesh.p / 6.283 var rad = min(view.layout.width, view.layout.height)/2; pos = vec2(view.layout.width/2 + rad * uv.x, view.layout.height/2 + rad * uv.y) return vec4(pos, 0, 1) * view.totalmatrix * view.viewmatrix } this.color = function(){ var f = sin(mesh.side*3.1415); var edge = 1-pow(f,.50); var aaedge = pow(f,0.2); //return vec4(view.hover, edge,0,1); var color = colorlib.hsva(vec4(off, 1, 1, 1)); var edgecolor = vec4(1,1,1,1); var mixed = mix(color, edgecolor, view.hover*edge); mixed.a *= aaedge; return mixed; } this.update = function(){ var view = this.view var width = view.layout?view.layout.width:view.width var height = view.layout?view.layout.height:view.height var cx = width/2; var cy = height/2; var radius = Math.min(cx,cy); this.mesh = this.vertexstruct.array() var cnt = 100; for (var i = 0;i<cnt;i++) { this.mesh.push(i*6.283/(cnt-1), 0); this.mesh.push(i*6.283/(cnt-1), 1); } } }) define.class(this, 'fgfill', this.Shader, function(){ this.draworder = 2; this.vertexstruct = define.struct({ p:vec2, }) this.mesh = this.vertexstruct.array() this.update = function(){ var view = this.view var width = view.layout? view.layout.width: view.width var height = view.layout? view.layout.height: view.height var cx = width/2; var cy = height/2; var radius = Math.min(cx,cy); this.mesh = this.vertexstruct.array() //this.mesh.push(view.basehue, vec3(0,0.5,0),0); this.mesh.push(-1,-1); this.mesh.push( 1,-1); this.mesh.push( 1, 1); this.mesh.push(-1,-1); this.mesh.push( 1, 1); this.mesh.push(-1, 1); } this.position = function(){ var huepos = vec2(sin(view.basehue * PI * 2 + mesh.p.x*.1), cos(view.basehue* PI * 2 + mesh.p.x*.1)) * (mesh.p.y*0.15 + 0.85) * 100; pos = vec2(min(view.layout.width, view.layout.height))/2.0 ; pos += huepos; return vec4(pos, 0, 1) * view.totalmatrix * view.viewmatrix } this.color = function(){ var D = abs(mesh.p.x); var alpha = vec4(view.contrastcolor.xyz,0); return mix(view.currentcolor, mix(view.contrastcolor, alpha, smoothstep(0.9, 1.0, D)), smoothstep(0.6, 1.0, D)); //if (D<0.7) return view.currentcolor; //if (D<1.0) return view.contrastcolor; //return vec4(1.,1.,1.,0.); } }) this.bgfill = true this.fgfill = true }) define.class(this, 'squareview', function($ui$view){ this.name = 'squareview' this.width = 200; this.height = 200; this.bgcolor = NaN this.attributes = { basehue: Config({type:float, value:0.7}), basesat: Config({type:float, value:0.7}), baseval: Config({type:float, value:0.7}), currentcolor: Config({type:vec4, value:"white"}), contrastcolor: Config({type:vec4, value: vec4("white")}), draggersize: Config({type:float, value: 8}), hover: Config({type:float, motion:"linear", duration:0.1, value:1}) } this.updatecolorfrompointer = function(p){ var p2 = vec2(p[0] - this.layout.width/2, p[1] - this.layout.height/2); var satpos = vec2(Math.sin(this.basehue * PI * 2 + PI/4), Math.cos(this.basehue* PI * 2 + PI/4)); var valpos = vec2(Math.sin(this.basehue * PI * 2 + PI/4 + PI/2), Math.cos(this.basehue* PI * 2 + PI/4 + PI/2)); var sidelen = Math.sqrt((140*140)/2); var sat = (vec2.dot(satpos, p2) + sidelen/2)/sidelen; var val = 1 - (vec2.dot(valpos, p2) + sidelen/2)/sidelen; sat = Math.max(0, Math.min(1, sat)); val = Math.max(0, Math.min(1, val)); this.basesat = sat; this.baseval = val; this.outer.setSatBase(sat); this.outer.setLumBase(val); } this.pointerend = this.pointermove = function(event){ var p = this.globalToLocal(event.position) this.updatecolorfrompointer(p); } define.class(this, 'fgfill', this.Shader, function(){ this.draworder = 5 this.vertexstruct = define.struct({ p:vec2, }) this.mesh = this.vertexstruct.array() this.update = function(){ var view = this.view var width = view.layout?view.layout.width:view.width var height = view.layout?view.layout.height:view.height var cx = width/2; var cy = height/2; var radius = Math.min(cx,cy); this.mesh = this.vertexstruct.array() //this.mesh.push(view.basehue, vec3(0,0.5,0),0); this.mesh.push(-1,-1); this.mesh.push( 1,-1); this.mesh.push( 1, 1); this.mesh.push(-1,-1); this.mesh.push( 1, 1); this.mesh.push(-1, 1); } this.position = function(){ huepos = vec2(sin(view.basehue * PI * 2), cos(view.basehue* PI * 2)) * 0.7 * 100; var satdir = vec2(sin((view.basehue - 1./4.) * PI * 2. ), cos((view.basehue - 1./4.)* PI * 2.)) * 0.7 * 100.0; var valdir = vec2(sin((view.basehue - 3./4.) * PI * 2.), cos((view.basehue - 3./4.)* PI * 2.)) * 0.7 * 100.0; huepos += (satdir - huepos )* (1-view.basesat) + (valdir - huepos ) * (1 - view.baseval); pos = vec2(min(view.layout.width, view.layout.height))/2 + mesh.p * view.draggersize; pos += huepos; return vec4(pos, 0, 1) * view.totalmatrix * view.viewmatrix } this.color = function(){ var D = sqrt(dot(mesh.p, mesh.p)); if (D<0.7) return view.currentcolor; if (D<1.0) return view.contrastcolor; return vec4(1.,1.,1.,0.); } }) this.fgfill = true define.class(this, 'bgfill', this.Shader, function(){ this.draworder = 1 this.vertexstruct = define.struct({ p:float, hsvoff: vec3, center: float }) this.mesh = this.vertexstruct.array() this.drawtype = this.TRIANGLES this.position = function(){ off = mesh.p / 6.283 var rad = min(view.layout.width, view.layout.height)/2; uv = vec2(sin(mesh.p * PI * 2), cos(mesh.p* PI * 2)) * 0.7; pos = vec2(view.layout.width/2 + rad * uv.x, view.layout.height/2 + rad * uv.y) return vec4(pos, 0, 1) * view.totalmatrix * view.viewmatrix } this.color = function(){ var edge = 1-pow(mesh.center,1.); var aaedge = pow(mesh.center,2.0); var hsv = vec3(view.basehue,1,1) + mesh.hsvoff; var color = colorlib.hsva(vec4(hsv, 1));; var edgecolor = vec4(1,1,1,1); var mixed = mix(color, edgecolor, view.hover*edge); //mixed.a *= aaedge; return color; } this.update = function(){ var view = this.view var width = view.layout?view.layout.width:view.width var height = view.layout?view.layout.height:view.height var cx = width/2; var cy = height/2; var radius = Math.min(cx,cy); this.mesh = this.vertexstruct.array() //this.mesh.push(view.basehue, vec3(0,0.5,0),0); this.mesh.push(view.basehue, vec3( 0, 0, 0),1); this.mesh.push(view.basehue + 1/4, vec3( 0,0,-1),1); this.mesh.push(view.basehue + 2/4, vec3( 0,-1,-1),1); this.mesh.push(view.basehue, vec3( 0, 0, 0),1); this.mesh.push(view.basehue + 2/4, vec3( 0, -1,-1),1); this.mesh.push(view.basehue + 3/4, vec3( 0, -1, 0),1); } }) this.bgfill = true }) define.class(this, 'colorarea', function($ui$view){ this.hardrect ={ color:function(){ return vec4(mesh.x, mesh.y,0,1); } }; this.width = 100; this.height = 100; }) this.layout = function(){ this.value = this.value } this.render = function(){ var colorwheel = this.colorwheel ? view({margin:10, bgcolor:NaN, position:"relative", alignself:"center"}, view({bgcolor:NaN, width:200, height:200, padding:3}), this.colorcirclecontrol({position:"absolute",width:200, height:200}), this.squareview({basehue:this.basehue, position:"absolute"})) : []; var colorsliders = this.colorsliders ? view({bgcolor:NaN, flexdirection:"column", width:280}, this.customslider({name:"rslider",height: this.sliderheight, flex:1, hsvfrom:vec3(0,1,0), hsvto:vec3(0,1,0.5), offset:function(v){this.outer.setRed(v.value/255)}}), this.customslider({name:"gslider",height: this.sliderheight, flex:1, hsvfrom:vec3(0.33,1,0), hsvto:vec3(0.333,1,0.5), offset:function(v){this.outer.setGreen(v.value/255)}}), this.customslider({name:"bslider",height: this.sliderheight, flex:1, hsvfrom:vec3(0.666,1,0), hsvto:vec3(0.666,1,0.5), offset:function(v){this.outer.setBlue(v.value/255)}}),view({bgcolor:NaN}, view({flex:1, bgcolor:NaN},numberbox({title:"R", flex:1, minvalue:0, maxvalue:255, name:"textr",value:"100", fontsize:this.fontsize})), view({flex:1, bgcolor:NaN},numberbox({title:"G", flex:1, minvalue:0, maxvalue:255, name:"textg",value:"100", fontsize:this.fontsize})), view({flex:1, bgcolor:NaN},numberbox({title:"B", flex:1, minvalue:0, maxvalue:255, name:"textb",value:"100", fontsize:this.fontsize})) ), this.customslider({name:"hsvider",height: this.sliderheight, flex:1, hsvfrom:vec3(0.0,this.basesat,this.baseval), hsvto:vec3(1,this.basesat,this.baseval), offset:function(v){this.outer.setHueBase(v.value/255)}}), this.customslider({name:"sslider",height: this.sliderheight, flex:1, hsvhueadd: 1, hsvfrom:vec3(0,0,this.baseval), hsvto:vec3(0,1,this.baseval), offset:function(v){this.outer.setSatBase(v.value/255)}}), this.customslider({name:"lslider",height: this.sliderheight, flex:1, hsvhueadd: 1, hsvfrom:vec3(0,this.basesat,0), hsvto:vec3(0,this.basesat,1), offset:function(v){this.outer.setLumBase(v.value/255)}}), view({bgcolor:NaN}, view({flex:1, bgcolor:NaN},numberbox({title:"H", flex:1, minvalue:0, maxvalue:100,fontsize:this.fontsize,name:"texth",value:"100"})), view({flex:1, bgcolor:NaN},numberbox({title:"S", flex:1, minvalue:0, maxvalue:100,fontsize:this.fontsize,name:"texts",value:"300"})), view({flex:1, bgcolor:NaN},numberbox({title:"V", flex:1, minvalue:0, maxvalue:100,fontsize:this.fontsize,name:"textv",value:"100"})))) : []; var colorbox = this.colorbox ? view({ bgcolor:NaN,justifycontent:"flex-end", flexdirection:"row", alignitems:"flex-end"}, view({ bgcolor:NaN,bgcolor:"transparent", margin:2,borderwidth:1, borderradius:1, bordercolor:this.internalbordercolor,flex:1, padding:1}, view({flex:1, bgcolor:NaN,alignitems:"flex-end",justifycontent:"flex-end"}, label({bgcolor:NaN,fontsize:this.fontsize, margin:vec4(10,5,0,0),text:"#", fgcolor:this.contrastcolor, fontsize: this.fontsize}), textbox({ name:"hexcolor", bgcolor:NaN, margin:vec4(0,5,0,0), value:"ff00ff", fgcolor:this.contrastcolor, padding:vec4(20,2,2,2), fontsize: this.fontsize })), view({flex:1, bgcolor:NaN,alignitems:"flex-end",justifycontent:"flex-end"}, label({bgcolor:NaN,fontsize:this.fontsize, margin:vec4(10,5,0,0),text:"alpha", fgcolor:this.contrastcolor, fontsize: this.fontsize}), textbox({name:"texta", bgcolor:NaN, margin:vec4(0,5,0,0), value:"128", fgcolor:this.contrastcolor, padding:vec4(20,2,2,2), fontsize: this.fontsize}) ) ) ): []; return [ view({flexdirection:"column", flex:1,alignitems:"center", justifycontent:"center", bgcolor:"transparent"}, colorwheel, colorsliders), colorbox ] } var colorpicker = this.constructor // Basic usage of the button. this.constructor.examples = { Usage:function(){ return [ colorpicker({width:300}) ] } } })