/* Copyright 2017 Jocly * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * As a special exception, the copyright holders give permission to link the * code of portions of this program with the OpenSSL library under certain * conditions as described in each individual source file and distribute * linked combinations including the program with the OpenSSL library. You * must comply with the GNU Affero General Public License in all respects * for all of the code used other than as permitted herein. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you do not * wish to do so, delete this exception statement from your version. If you * delete this exception statement from all source files in the program, * then also delete it in the license file. */ exports.view = View = { Game: {}, Board: {}, }; if(window.JoclyXdViewCleanup) window.JoclyXdViewCleanup(); (function() { window.JoclyXdViewCleanup = function() { var renderer = threeCtx && threeCtx.renderer; if(renderer) { renderer.forceContextLoss(); renderer.context = null; renderer.domElement = null; delete threeCtx.renderer; } if(arStream) AR(null); $(document).unbind("joclyhub.webrtc",WebRTCHandler); } var area, currentSkin, logger, xdv, VSIZE, VHALF, htStateMachine, threeCtx = null, SCALE3D = 0.001, resourcesMap = {}, resources, arStream = null; // hack to ensure mouse and touch events do not collide var lastTouchStart=0, lastJoclyclick=0; /* ======================================== */ var LOADING_TEXT_RESOURCE=""; if(typeof JoclyHub!="undefined") { LOADING_TEXT_RESOURCE=JoclyHub.hubPath+"/res/images/loading-txt.png"; } else if(typeof JoclyPlazza!="undefined") { LOADING_TEXT_RESOURCE=JoclyPlazza.config.baseURL+JoclyPlazza.config.pzPath+"/images/loading-txt.png"; } if(typeof CustomEvent == "undefined") { function CustomEvent ( event, params ) { params = params || { bubbles: false, cancelable: false }; var evt = document.createEvent( 'Event' ); evt.initEvent( event, params.bubbles, params.cancelable ); return evt; }; CustomEvent.prototype = window.Event.prototype; window.CustomEvent = CustomEvent; } var Class = function() { }; (function() { var initializing = false, fnTest = /xyz/.test(function() { }) ? /\b_super\b/ : /.*/; Class.extend = function(prop) { var _super = this.prototype; initializing = true; var prototype = new this(); initializing = false; for ( var name in prop) { prototype[name] = typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ? (function(name, fn) { return function() { var tmp = this._super; this._super = _super[name]; var ret = fn.apply(this, arguments); this._super = tmp; return ret; }; })(name, prop[name]) : prop[name]; } function Class(args) { if (!initializing && this.init) if (arguments.length > 0 && args.jBlocksArgsList) this.init.apply(this, args); else this.init.apply(this, arguments); } Class.prototype = prototype; Class.prototype.constructor = Class; Class.extend = arguments.callee; return Class; }; })(); /* ======================================== */ var WebRTC; if(typeof JoclyPlazza!="undefined") { logger=JoclyPlazza.getLogger("htsm","logHTSM"); WebRTC=JoclyPlazza.webrtc; } else if(typeof JoclyHub!="undefined") WebRTC=JoclyHub.webrtc; var logResourcesLoad=false; function Log() { console.info.apply(console,arguments); } View.Board.Log = Log; View.Game.Log = Log; function HTStateMachine() {} HTStateMachine.prototype=new JHStateMachine(); HTStateMachine.prototype.smError=function() { if(typeof JoclyPlazza!="undefined" || (JoclyHub && JoclyHub.request.debughtsm)) { Log.apply(null,arguments); }; } HTStateMachine.prototype.smWarning=function() { if(typeof JoclyPlazza!="undefined" || (JoclyHub && JoclyHub.request.debughtsm)) { Log.apply(null,arguments); } }; HTStateMachine.prototype.smDebug=function() { if(typeof JoclyPlazza!="undefined" || (typeof JoclyHub!="undefined" && JoclyHub.request.debughtsm)) { Log.apply(null,arguments); } } function Diff(oOld,oNew) { var diff={}; var diffSet=false; for(var i in oNew) { if(oNew.hasOwnProperty(i)) { if(!oOld.hasOwnProperty(i)) { diff[i]=oNew[i]; diffSet=true; } else if(typeof oNew[i]=="object") { var diff0=Diff(oOld[i],oNew[i]); if(diff0) { diff[i]=diff0; diffSet=true; } } else if(oNew[i]!=oOld[i]) { diff[i]=oNew[i]; diffSet=true; } } } return diffSet?diff:null; } var resLoadingMask=null; var resLoadingCount=0; function IncrementResLoading() { if(resLoadingCount++==0) { resLoadingMask=$(".jocly-res-loading-mask"); if(resLoadingMask.length==0) resLoadingMask=$("
").addClass("jocly-res-loading-mask").css({ position: "absolute", top: 0, left: 0, width: $("body").width(), height: $("body").height(), "background-color": "rgba(0,0,0,.8)", "background-image": "url("+LOADING_TEXT_RESOURCE+")", "background-position": "center center", "background-repeat": "no-repeat", "z-index": 100000, }).appendTo($("body")); else resLoadingMask.show(); } } function DecrementResLoading() { if(--resLoadingCount==0) { if(resLoadingMask) resLoadingMask.hide(); } } var materialMaps={}; function GetMaterialMap(map,callback) { var $this=this; if(materialMaps[map]) callback(materialMaps[map]); else{ var loader = new THREE.TextureLoader(); loader.setCrossOrigin("anonymous"); if(logResourcesLoad) console.log("Loading map",map); IncrementResLoading(); console.info("TODO map",map); loader.load( // ressource url map, // Function when resource is loaded function(texture){ materialMaps[map]=texture; if(logResourcesLoad) console.log("Loaded",map); DecrementResLoading(); threeCtx.animControl.trigger(); callback(materialMaps[map]); }, // Function called when download progresses function ( xhr ) { //console.log( (xhr.loaded / xhr.total * 100) + '% loaded' ); }, // Function called when download errors function ( xhr ) { if(logResourcesLoad) console.log("(not) Loaded",map); DecrementResLoading(); threeCtx.animControl.trigger(); callback(null); }); } } var pendingGetResource=[]; function GetResource(res,callback) { var resource=resources[res]; if(resource===undefined) { resource=resources[res]={ pending: [callback], status: "loading", } var getResFnt=null; var m=/^(.*\|)(.*?)$/.exec(res); if(m) { var prefix=m[1]; var url=m[2]; for(var r in resourcesMap) { var m2=/^(.*\|)(.*?)$/.exec(r); if(m2) if(prefix==m[1] && url.substr(-m2[2].length)==m2[2]) { getResFnt=resourcesMap[r]; break; } } } if(/^image\|/.test(res)) { var imgSrc=/^image\|(.*)/.exec(res)[1]; if(logResourcesLoad) console.log("Loading resource",res); function HandleImage(image) { resource.image=image; if(logResourcesLoad) console.log("Loaded",res); resource.status="loaded"; resource.imgSrc=imgSrc; DecrementResLoading(); for(var i=0;i 0){ var modifier = new THREE.SubdivisionModifier( smooth ); modifier.modify( geometry ); } resource.status="loaded"; DecrementResLoading(); resource.geometry=geometry; resource.materials=materials; for(var i=0;i").attr("type","text/javascript").attr("jocly-type","json-resource").attr("src",url).appendTo($("head")); } else if(/^json2\|/.test(res)) { if(logResourcesLoad) console.log("Loading resource",res); IncrementResLoading(); var url=/^json2\|(.*)/.exec(res)[1]; var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (xhr.readyState == XMLHttpRequest.DONE) { if(logResourcesLoad) console.log("Loaded",res); var data = JSON.parse(xhr.responseText); resource.status="loaded"; DecrementResLoading(); resource.data=data; for(var i=0;i0) { if(options.base===undefined) options.base={}; options.base.ratio=this.ratio; options.base.center=this.center; } this.gadgets[id] = new Gadget(id,options); }, updateGadget: function(id, options, delay, callback) { var gadget = this.gadgets[id]; if (gadget) { if(arguments.length<3 || delay===undefined) delay=0; if(arguments.length<4 || callback===undefined) callback=function() {} gadget.update(options,delay,callback); } }, removeGadget: function(id) { var gadget = this.gadgets[id]; if (gadget) { gadget.unbuild(); delete this.gadgets[id]; } }, showGadget: function(id) { this.updateGadget(id,{ base: { visible: true, }, }); }, hideGadget: function(id) { this.updateGadget(id,{ base: { visible: false, }, }); }, updateArea: function(ratio,center) { this.ratio=ratio; this.center=center; for ( var gi in this.gadgets) this.gadgets[gi].update({ base: { ratio: ratio, center: center, }, }); }, redisplayGadgets: function() { for ( var gi in this.gadgets) { var gadget = this.gadgets[gi]; gadget.update({}); } }, unbuildGadgets: function() { for ( var gi in this.gadgets) this.gadgets[gi].unbuild(); }, saveGadgetProps: function(id, props, saveName) { var gadget = this.gadgets[id]; if (gadget) gadget.saveProps(props, saveName); }, restoreGadgetProps: function(id, saveName, delay, callback) { var gadget = this.gadgets[id]; if (gadget) gadget.restoreProps(saveName,delay,callback); else if(callback) callback(); }, listScene: function(){ console.log("listScene:"); var accu=[]; accu["faces"]=0; //var crlf="
"; var crlf=" :: "; var output="========= Scene summary ==========="; var nbLights=-1; function getFaces(obj,nbFaces){ if(obj.geometry){ var gg=obj.geometry; if (gg.faces) nbFaces+=gg.faces.length; } if(obj.getDescendants){ var children=obj.getDescendants(); if (children) nbFaces+=getFaces(children,nbFaces); } return nbFaces; } if(threeCtx)if(threeCtx.scene){ var threeScene=threeCtx.scene; nbLights=threeScene.__lights.length; console.log(threeScene); var obj=threeScene.getDescendants(); for (var o in obj){ var nbf=getFaces(obj[o],0); accu["faces"]+=nbf; //console.log(obj[o].name+" has "+nbf+" faces"); /*if(obj[o].geometry){ var gg=obj[o].geometry; if (gg.faces) accu["faces"]+=gg.faces.length; console.log(obj[o].name+" has "+gg.faces.length+" faces"); }*/ } } output+=crlf+"nb lights: "+nbLights; output+=crlf+"Nb faces: "+ accu["faces"]; console.log(output); }, }) /* ======================================== */ function InitGlobals() { xdv = new XDView(); VSIZE = 12600; VHALF = VSIZE/2; htStateMachine = null; threeCtx = null; SCALE3D = 0.001; resourcesMap = {}; resources={}; area=null; currentSkin=null; logger=null; } InitGlobals(); /* ======================================== */ var Gadget=Class.extend({ init: function(id, options) { this.id = id; this.options = $.extend(true, { base: { visible: false, } }, options); this.avatar=null; this.savedProps={}; }, mergeOptions: function() { return $.extend(true, { x: 0, y: 0, z: 0, }, this.options.base, currentSkin["3d"]?this.options["3d"]:this.options["2d"], this.options[currentSkin.name]); }, build: function(options) { if(this.avatar) return; if(arguments.length==0) options=this.mergeOptions(); }, unbuild: function() { if(this.avatar) { this.avatar.remove(); this.avatar=null; } }, canDisplay: function(options) { if(currentSkin===undefined || currentSkin===null) return false; if(arguments.length==0) options=this.mergeOptions(); return options.visible && ((!currentSkin["3d"] && options.ratio!==undefined && options.center!==undefined) || (currentSkin["3d"] /* && 3D requirements */)); }, update: function(options,delay,callback) { if(arguments.length<2 || delay===undefined) delay=0; if(arguments.length<3 || callback===undefined) callback=function(){}; if(currentSkin!==undefined && currentSkin!==null) { var xdMap=currentSkin["3d"]?"3d":"2d"; if(options.base) for(var i in options.base) { if(this.options[xdMap]) delete this.options[xdMap][i]; if(this.options[currentSkin.name]) delete this.options[currentSkin.name][i]; } if(options[xdMap]) for(var i in options[xdMap]) if(this.options[currentSkin.name]) delete this.options[currentSkin.name][i]; $.extend(true,this.options,options); var aOptions=this.mergeOptions(); if(!this.avatar && this.canDisplay(aOptions)) { var avatarType=avatarTypes[aOptions.type]; if(avatarType!==undefined) this.avatar=new avatarType(this,aOptions); } if(typeof delay=="object") { if(delay[currentSkin.name]!==undefined) delay=delay[currentSkin.name]; else if(delay[xdMap]!==undefined) delay=delay[xdMap]; else if(delay.base!==undefined) delay=delay.base; else delay=0; } if(this.avatar) this.avatar.update(aOptions,delay,callback); } else $.extend(true,this.options,options); }, saveProps: function(props, saveName) { var save={}; for(var oi in this.options) { var optCat=this.options[oi]; for(var i in props) { var prop=props[i]; if(optCat[prop]!==undefined) { save[oi]=save[oi] || {}; save[oi][prop]=optCat[prop]; } } } this.savedProps[saveName]=save; }, restoreProps: function(saveName,delay,callback) { if (this.savedProps[saveName]!==undefined) this.update(this.savedProps[saveName],delay,callback); else if(callback) callback(); }, }); /* ======================================== */ var updateOp=1; var GadgetAvatar=Class.extend({ init: function(gadget,options) { this.gadget = gadget; this.options = options; this.SCALE3D = SCALE3D; this.animCounts={}; }, remove: function() { }, display: function(options) { }, update: function(options,delay,callback) { var aOptions=$.extend(true,{},this.options,options); aOptions.updateOp=updateOp++; aOptions.updateCallback=callback; this.display(aOptions,delay,callback); if(aOptions.visible) this.show(); else this.hide(); this.options=aOptions; }, show: function() { }, hide: function() { }, animStart: function(options) { if(options===undefined) { console.error("animStart without options"); debugger; return; } if(options.updateOp===undefined) { console.error("animStart without options"); debugger; return; } if(this.object3d) this.object3d.matrixAutoUpdate = true; if(this.animCounts[options.updateOp]===undefined) this.animCounts[options.updateOp]=1; else this.animCounts[options.updateOp]++; }, animEnd: function(options) { if(options===undefined) { console.error("animEnd without options"); debugger; return; } if(options.updateOp===undefined) { console.error("animEnd without options"); debugger; return; } if(this.animCounts[options.updateOp]===undefined) { console.error("animEnd without animCount"); debugger; return; } if(--this.animCounts[options.updateOp]==0) { if(this.object3d) this.object3d.matrixAutoUpdate = false; options.updateCallback(); delete this.animCounts[options.updateOp]; } }, getResource : GetResource, }); var GadgetElement=GadgetAvatar.extend({ init: function(gadget,options) { options=$.extend(true,{ display: function() {}, },options); this._super.apply(this,arguments); this.options = $.extend(true, { x : 0, y : 0, z : 0, width : 1000, height : 1000, tag: "div", opacity : 1, rotate: 0, css: {}, }, options); this.element = $("<"+this.options.tag+"/>").css({ "position" : "absolute", "z-index" : this.options.z, }).hide().addClass("jocly-gadget").appendTo(area); if(this.options.initialClasses) this.element.addClass(this.options.initialClasses); }, display: function(options,delay) { var $this=this; if(this.element) { this.displayElement.call(this,!this.displayCalled,options,delay); this.displayCalled=true; } else if(delay) { this.animStart(options); setTimeout(function() { $this.animEnd(options); },delay); } }, displayElement: function(force,options,delay) { var $this=this; this.element.css($.extend(true,this.options.css,options.css)); if( force || this.aWidth===undefined || this.aHeight===undefined || options.ratio != this.options.ratio || options.center.x != this.options.center.x || options.center.y != this.options.center.y || options.width != this.options.width || options.height != this.options.height || options.x != this.options.x || options.y != this.options.y || options.z != this.options.z ) { this.aWidth = options.width * options.ratio; this.aHeight = options.height * options.ratio; var left = options.x * options.ratio + options.center.x - this.aWidth / 2; var top = options.y * options.ratio + options.center.y - this.aHeight / 2; if(delay) { this.animStart(options); this.element.css({ "z-index": options.z, }).animate({ width : this.aWidth, height : this.aHeight, left : left, top : top, },delay,function() { $this.animEnd(options); }); } else { this.element.css({ width : this.aWidth, height : this.aHeight, left : left, top : top, "z-index": options.z, }); } this.options.display(this.element,this.aWidth,this.aHeight); } if(force || options.classes != this.options.classes) { if(this.options.classes) this.element.removeClass(this.options.classes); this.element.addClass(options.classes); } if(force || options.click != this.options.click) { //this.element.unbind(JocGame.CLICK); this.element.unbind(JocGame.MOUSEMOVE_EVENT); this.element.unbind(JocGame.MOUSEDOWN_EVENT); this.element.unbind(JocGame.MOUSEUP_EVENT); if(options.click) { var iOS = ( navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? true : false ); (function() { var mouseDown=false; var notified=false; var downPosition=[0,0]; $this.element.bind(JocGame.MOUSEDOWN_EVENT,function(event) { event.preventDefault(); if(iOS && event.type=="mousedown") return; if(event.type=="touchstart") lastTouchStart = Date.now(); if(event.type=="mousedown" && Date.now()-lastTouchStart<500) return; mouseDown=true; downPosition=GetEventPosition(event); }); $this.element.bind(JocGame.MOUSEUP_EVENT,function(event) { event.preventDefault(); if(iOS && event.type=="mouseup") return; mouseDown=false; if(event.type=="joclyclick") lastJoclyclick = Date.now(); if(event.type=="mouseup" && Date.now()-lastJoclyclick<500) return; if(event.type=='mouseup' || event.type=='joclyclick') { options.click.call($this); } else { event.stopPropagation(); var newevent = new CustomEvent("joclyclick",{}); var x, y; if(event.originalEvent.changedTouches && event.originalEvent.changedTouches.length>0) { x = event.originalEvent.changedTouches[0].pageX; y = event.originalEvent.changedTouches[0].pageY; } else if(event.originalEvent.touches && event.originalEvent.touches.length>0) { x = event.originalEvent.touches[0].pageX; y = event.originalEvent.touches[0].pageY; } else { console.warn("Invalid touch event"); return; } var target = document.elementFromPoint(x, y); target.dispatchEvent(newevent); } }); $this.element.bind(JocGame.MOUSEMOVE_EVENT,function(event) { event.preventDefault(); if(iOS && event.type=="mousemove") return; if(mouseDown && !notified) { var position=GetEventPosition(event); var dx=position[0]-downPosition[0]; var dy=position[1]-downPosition[1]; if(dx*dx+dy*dy>100) { notified=true; options.click.call($this); } } }); })(); } } /* if(force || options.holdClick != this.options.holdClick) { this.element.unbind("holdclick"); if(options.holdClick) this.element.bind("holdclick",options.holdClick); } */ if(force || options.rotate != this.options.rotate) { while(options.rotate<0) options.rotate+=360; options.rotate%=360; var rotate=options.rotate; var rotate0=this.options.rotate; if(rotate-this.options.rotate>180) rotate0=360; else if(this.options.rotate-rotate>180) rotate+=360; if(delay) { this.animStart(options); $({deg:rotate0}).animate({deg:rotate},{ step: function(now) { $this.element.css('transform','rotate('+now+'deg)'); }, duration: delay, complete: function() { $this.animEnd(options); }, }); } else this.element.css({ "transform": "rotate("+options.rotate+"deg)", }); } else if(delay) { this.animStart(options); setTimeout(function() { $this.animEnd(options); },0); } if(force || options.opacity != this.options.opacity) { if(delay) { this.animStart(options); this.element.stop().animate({ "opacity": options.opacity, },delay,function() { $this.animEnd(options); }); } else this.element.css({ "opacity": options.opacity, }); } }, show: function() { this.element.show(); }, hide: function() { this.element.hide(); }, remove: function() { this._super.apply(this,arguments); this.element.unbind(JocGame.CLICK); //this.element.unbind("holdclick"); this.element.remove(); }, }); var GadgetImage=GadgetElement.extend({ displayElement: function(force,options) { var $this=this; this._super.apply(this,arguments); if(force || this.options.file!=options.file) { this.options.file=options.file; GetResource("image|"+options.file, function(image,imgSrc) { if(imgSrc==$this.options.file) $this.element.css({ "background-image" : "url(" + image.src + ")", "background-size" : "100% 100%", "background-repeat" : "no-repeat", }); else console.log("file has changed to",$this.options.file,"(",imgSrc,")"); }); } }, }); var GadgetCanvas=GadgetElement.extend({ init: function(gadget,options) { options=$.extend({ tag: "canvas", draw: function() {}, },options); this._super.call(this,gadget,options); this.canvasContext=this.element[0].getContext("2d"); }, displayElement: function(force,options) { this._super.apply(this,arguments); this.element.attr("width",this.aWidth).attr("height",this.aHeight); //this.canvasContext.save(); this.canvasContext.clearRect(0,0,options.width,options.height); this.canvasContext.translate(this.aWidth/2,this.aHeight/2); this.canvasContext.scale(options.ratio,options.ratio); this.options.draw.call(this,this.canvasContext,1/options.ratio); //this.canvasContext.restore(); } }); var GadgetHexagon=GadgetCanvas.extend({ init: function(gadget,options) { var $this=this; var R=options.radius; var L=R*Math.sqrt(3)/2; options=$.extend({ lineWidthFactor: 1, },options,{ draw: function(ctx,pixSize) { ctx.lineWidth=pixSize*$this.options.lineWidthFactor; ctx.beginPath(); ctx.moveTo(-L,L/2); ctx.lineTo(0,R); ctx.lineTo(L,L/2); ctx.lineTo(L,-L/2); ctx.lineTo(0,-R); ctx.lineTo(-L,-L/2); ctx.closePath(); if($this.options.strokeStyle) { ctx.strokeStyle=$this.options.strokeStyle; ctx.stroke(); } if($this.options.fillStyle) { ctx.fillStyle=$this.options.fillStyle; ctx.fill(); } }, }); this._super.call(this,gadget,options); this.element.attr("width",options.width).attr("height",options.height); this.canvasContext=this.element[0].getContext("2d"); }, }); /* var GadgetSprite=GadgetCanvas.extend({ init: function(gadget,options) { this._super.apply(this,arguments); this.displayArgs=null; }, displayElement: function(force,options) { var $this=this; this._super.apply(this,arguments); if(force || this.options.file!=options.file) { GetResource("image|"+options.file, function(image) { $this.image=image; if($this.displayArgs && $this.options.clipx!==undefined && $this.options.clipy!==undefined && $this.options.clipwidth!==undefined && $this.options.clipheight!==undefined) $this.drawImage.apply($this,$this.displayArgs); }); } if(force || this.options.clipx!=options.clipx || this.options.clipy!=options.clipy || this.options.clipwidth!=options.clipwidth || this.options.clipheight!=options.clipheight ) { if(this.image && options.clipx!==undefined && options.clipy!==undefined && options.clipwidth!==undefined && options.clipheight!==undefined) { this.drawImage.call(this,force,options); } else this.displayArgs=arguments; } if(this.image && options.clipx!==undefined && options.clipy!==undefined && options.clipwidth!==undefined && options.clipheight!==undefined) this.drawImage.apply(this,arguments); else this.displayArgs=arguments; }, drawImage: function(force,options) { this.canvasContext.save(); var x0=parseInt(options.clipx+.5); var y0=parseInt(options.clipy+.5); var cx0=parseInt(options.clipwidth+.5); var cy0=parseInt(options.clipheight+.5); var x1=0; var y1=0; var cx1=parseInt(this.aWidth+.5); var cy1=parseInt(this.aHeight+.5); this.canvasContext.scale(cx1,cy1); this.canvasContext.imageSmoothingEnabled=true; this.canvasContext.drawImage(this.image,x0,y0,cx0,cy0,x1,y1,1,1); //this.canvasContext.drawImage(this.image,x0,y0,cx0,cy0,x1,y1,cx1,cy1); this.canvasContext.restore(); this.displayArgs=null; }, }); */ var GadgetSprite=GadgetCanvas.extend({ init: function(gadget,options) { this._super.apply(this,arguments); this.displayArgs=null; }, displayElement: function(force,options) { var $this=this; this._super.apply(this,arguments); if(force || this.options.file!=options.file) { GetResource("image|"+options.file, function(image,imgSrc) { if(imgSrc==$this.options.file){ $this.image=image; $this.element.css({ "background-image" : "url(" + image.src + ")", "background-size" : "100% 100%", "background-repeat" : "no-repeat", }); } if($this.displayArgs && $this.options.clipx!==undefined && $this.options.clipy!==undefined && $this.options.clipwidth!==undefined && $this.options.clipheight!==undefined) $this.drawImage.apply($this,$this.displayArgs); }); } if(force || this.options.clipx!=options.clipx || this.options.clipy!=options.clipy || this.options.clipwidth!=options.clipwidth || this.options.clipheight!=options.clipheight ) { if(this.image && options.clipx!==undefined && options.clipy!==undefined && options.clipwidth!==undefined && options.clipheight!==undefined) { this.drawImage.call(this,force,options); } else this.displayArgs=arguments; } if(this.image && options.clipx!==undefined && options.clipy!==undefined && options.clipwidth!==undefined && options.clipheight!==undefined) this.drawImage.apply(this,arguments); else this.displayArgs=arguments; }, drawImage: function(force,options) { var rx=(options.clipwidth/this.aWidth); var ry=(options.clipheight/this.aHeight); var bcx=parseInt(this.image.width/rx+.5); var bcy=parseInt(this.image.height/ry+.5); var bs= ""+bcx+"px "+bcy+"px"; this.element.css({ "width" : parseInt(this.aWidth+.5), "height" : parseInt(this.aHeight+.5), "background-image" : options.file, "background-size" : bs, "background-position": "-"+(parseInt(options.clipx/rx+.5))+"px -"+(parseInt(options.clipy/ry+.5))+"px", }); }, }); var GadgetDisk=GadgetElement.extend({ init: function(gadget,options) { this._super.apply(this,arguments); }, displayElement: function(force,options) { this._super.apply(this,arguments); this.element.css({ "border-radius": "50%", }); }, }); var GadgetObject3D=GadgetAvatar.extend({ init: function(gadget,options) { var $this=this; this._super.apply(this,arguments); this.displayCalled=false; this.options = $.extend(true, { x : 0.0, y : 0.0, z : 0.0, color: null, castShadow: true, receiveShadow: false, harbor: true, }, options); this.createObject(); }, createObject: function() { }, objectReady: function(object3d) { var $this=this; this.object3d=object3d; object3d.castShadow=this.options.castShadow; object3d.receiveShadow=this.options.receiveShadow; object3d.name=this.gadget.id; object3d.matrixAutoUpdate = false; this.shouldUpdate = true; this.update(this.options); //object3d.visible=this.options.visible; if(this.options.harbor) threeCtx.harbor.add(object3d); else threeCtx.scene.add(object3d); }, display: function(options,delay) { var $this=this; if(this.object3d) { this.shouldUpdate = false; this.displayObject3D.call(this,!this.displayCalled,options,delay); this.displayCalled=true; if(this.shouldUpdate) this.object3d.updateMatrix(); } if(delay) { $this.animStart(options); setTimeout(function() { $this.animEnd(options); },delay); } }, displayObject3D: function(force,options,delay) { var $this=this; threeCtx.animControl.trigger((isNaN(delay)?0:delay)+200); if(force || options.x != this.options.x || options.y != this.options.y || options.z != this.options.z ) { this.shouldUpdate = true; if(delay) { this.animStart(options); new TWEEN.Tween(this.object3d.position).to({ x: options.x*SCALE3D, y: options.z*SCALE3D, z: options.y*SCALE3D, },delay).easing(options.positionEasing?options.positionEasing:TWEEN.Easing.Cubic.EaseInOut).onComplete(function() { $this.animEnd(options); }).onUpdate(function(ratio) { if(options.positionEasingUpdate) options.positionEasingUpdate.call($this,ratio); }).start(); } else { this.object3d.position.x=options.x*SCALE3D; this.object3d.position.y=options.z*SCALE3D; this.object3d.position.z=options.y*SCALE3D; } } if(force || options.click != this.options.click) { if(this.options.click) this.object3d.off("mouseup"); if(options.click) { //if(!threeCtx.cameraControls.hasBeenDragged()) this.object3d.on("mouseup",function() { //if(!threeCtx.cameraControls.hasBeenDragged()) options.click.call(); }); } } /* if(force || options.holdClick != this.options.holdClick) { if(this.options.holdClick) this.object3d.off("holdclick"); if(options.holdClick) { //if(!threeCtx.cameraControls.hasBeenDragged()) this.object3d.on("holdclick",function(eventData){ if(!threeCtx.cameraControls.hasBeenDragged()) options.holdClick.call($this,eventData); } ); } } */ if(force || options.castShadow != this.options.castShadow) { this.object3d.castShadow=options.castShadow } if(force || options.receiveShadow != this.options.receiveShadow) { this.object3d.receiveShadow=options.receiveShadow } }, show: function() { if(arStream && !this.options.harbor) return this.hide(); if(this.object3d){ this.object3d.visible=true; if (this.object3d.children){ for(var c=0;c180) options.rotate-=360; else if(delta<-180) options.rotate+=360; delta=options.rotateX-this.options.rotateX; if(delta>180) options.rotateX-=360; else if(delta<-180) options.rotateX+=360; delta=options.rotateY-this.options.rotateY; if(delta>180) options.rotateY-=360; else if(delta<-180) options.rotateY+=360; if(delay) { this.animStart(options); new TWEEN.Tween(this.object3d.rotation).to({ x: options.rotateX * (Math.PI/180), y: options.rotate * (Math.PI/180), z: options.rotateY * (Math.PI/180), },delay).easing(options.rotateEasing?options.rotateEasing:TWEEN.Easing.Cubic.EaseInOut).onComplete(function() { $this.animEnd(options); }).start(); } else { this.object3d.rotation.x = options.rotateX * (Math.PI/180); this.object3d.rotation.y = options.rotate * (Math.PI/180); this.object3d.rotation.z = options.rotateY * (Math.PI/180); } } if(force || options.scale[0] != this.options.scale[0] || options.scale[1] != this.options.scale[1] || options.scale[2] != this.options.scale[2] ) { this.shouldUpdate = true; if(delay) { this.animStart(options); new TWEEN.Tween(this.object3d.scale).to({ x: options.scale[0], y: options.scale[2], z: options.scale[1], },delay).easing(options.scaleEasing?options.scaleEasing:TWEEN.Easing.Cubic.EaseInOut).onComplete(function() { $this.animEnd(options); }).start(); } else { this.object3d.scale.set(options.scale[0],options.scale[2],options.scale[1]); /*if ((options.scale[0] > 0) && (options.scale[1] > 0) && (options.scale[2] > 0) ) this.object3d.scale.set(options.scale[0],options.scale[2],options.scale[1]); else{ var g=this.object3d.geometry; g.dynamic = true; for(var i = 0; i0) { if(this.object3d.material && this.object3d.material.materials && this.object3d.material.materials.length>0 && !this.object3d.material.materials[0].morphTargets) { for(var i=0;i 0) { vStream.video = video; } else { vStream.ownVideoElement = true; vStream.video = $("