/*
3DHOP - 3D Heritage Online Presenter
Copyright (c) 2014-2023, Visual Computing Lab, ISTI - CNR
All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
SpiderGL.openNamespace();
//----------------------------------------------------------------------------------------
// CONSTANTS
//----------------------------------------------------------------------------------------
// version
const HOP_VERSION = "4.3.6";
// selectors
const HOP_ALL = 256;
// starting debug mode
const HOP_DEBUGMODE = false;
// default light direction
const HOP_DEFAULTLIGHT = [0, 0, -1];
// sgltrackball
const SGL_TRACKBALL_NO_ACTION = 0;
const SGL_TRACKBALL_ROTATE = 1;
const SGL_TRACKBALL_PAN = 2;
const SGL_TRACKBALL_DOLLY = 3;
const SGL_TRACKBALL_SCALE = 4;
Presenter = function (canvas) {
this._supportsWebGL = sglHandleCanvas(canvas, this, { stencil: true });
console.log("3DHOP version: " + this.version);
};
Presenter.prototype = {
//----------------------------------------------------------------------------------------
// PARSING FUNCTIONS
//----------------------------------------------------------------------------------------
_parseScene : function (options) {
options = options || { };
var r = {
background : this._parseBackground(options.background),
meshes : this._parseMeshes(options.meshes),
texturedQuads : this._parseTexturedQuads(options.texturedQuads),
modelInstances : this._parseModelInstances(options.modelInstances),
spots : this._parseSpots(options.spots),
trackball : this._parseTrackball(options.trackball),
space : this._parseSpace(options.space),
config : this._parseConfig(options.config)
};
return r;
},
_parseBackground : function (options) {
var r = sglGetDefaultObject({
image : null,
isEnvironment : false,
color : [ 0.0, 0.0, 0.0, 0.0 ]
}, options);
if (r.image) { this._objectsToProcess++; this._objectsToLoad++; }
return r;
},
_parseMeshes : function (options) {
var r = { };
for (var m in options) {
r[m] = this._parseMesh(options[m]);
}
return r;
},
_parseMesh : function (options) {
var r = sglGetDefaultObject({
url : null,
mType : null,
transform : null
}, options);
r.transform = this._parseTransform(r.transform);
if (r.url) { this._objectsToProcess++; this._objectsToLoad++; }
return r;
},
_parseTexturedQuads : function (options) {
var r = { };
for (var m in options) {
r[m] = this._parseTexturedQuad(options[m]);
}
return r;
},
_parseTexturedQuad : function (options) {
var r = sglGetDefaultObject({
url : null
}, options);
if (r.url) { this._objectsToProcess++; this._objectsToLoad++; }
return r;
},
_parseModelInstances : function (options) {
var r = { };
for (var m in options) {
r[m] = this._parseModelInstance(options[m]);
}
return r;
},
_parseModelInstance : function (options) {
var r = sglGetDefaultObject({
mesh : null,
rendermode : null,
color : [ 1.0, 1.0, 1.0 ],
useSolidColor : false,
specularColor : [ 0.0, 0.0, 0.0, 32.0 ],
backfaceColor : [ 0.7, 0.4, 0.4, 0.0 ],
alpha : 0.5,
useTransparency : false,
useLighting : true,
cursor : "default",
ID : 0,
transform : null,
visible : true,
tags : [ ],
clippable : true,
measurable : true,
}, options);
if (r.color[3]) //3DHOP 2.0 backward compatibility
{
r.alpha = r.color[3];
r.color = [r.color[0], r.color[1], r.color[2]]
}
r.transform = this._parseTransform(r.transform);
r.ID = this._instancesProgressiveID;
this._instancesProgressiveID++;
return r;
},
_parseSpots : function (options) {
var r = { };
for (var m in options) {
r[m] = this._parseSpot(options[m]);
}
return r;
},
_parseSpot : function (options) {
var r = sglGetDefaultObject({
mesh : null,
rendermode : null,
color : [ 0.0, 0.25, 1.0 ],
useSolidColor : true,
alpha : 0.5,
alphaHigh : 0.8,
useTransparency : true,
useStencil : false,
cursor : "pointer",
ID : 0,
transform : null,
visible : true,
tags : [ ]
}, options);
if (r.color[3]) //3DHOP 2.0 backward compatibility
{
r.alpha = r.color[3];
r.color = [r.color[0], r.color[1], r.color[2]]
}
r.transform = this._parseTransform(r.transform);
r.ID = this._spotsProgressiveID;
this._spotsProgressiveID++;
return r;
},
_parseTrackball : function (options) {
var r = sglGetDefaultObject({
type : TurnTableTrackball,
trackOptions : {},
locked : false,
dragSpeed : 1.0
}, options);
return r;
},
_parseSpace : function (options) {
var r = sglGetDefaultObject({
centerMode : "first",
radiusMode : "first",
whichInstanceCenter : "",
whichInstanceRadius : "",
explicitCenter : [0.0, 0.0, 0.0],
explicitRadius : 1.0,
transform : null,
cameraFOV : 60.0,
cameraNearFar : [0.01, 10.0],
cameraType : "perspective",
sceneLighting : true,
}, options);
r.transform = this._parseTransform(r.transform);
if(r.cameraFOV < 2.0) r.cameraFOV = 2.0;
if(r.cameraFOV > 88.0) r.cameraFOV = 88.0;
if((r.cameraType != "perspective") && (r.cameraType != "orthographic")) r.cameraType = "perspective";
return r;
},
_parseConfig : function (options) {
var r = sglGetDefaultObject({
pickedpointColor : [1.0, 0.0, 1.0],
measurementColor : [0.5, 1.0, 0.5],
showClippingPlanes : true,
showClippingBorder : false,
clippingBorderSize : 0.5,
clippingBorderColor : [0.0, 1.0, 1.0],
pointSize : 1.0,
pointSizeMinMax : [0.0, 2.0],
autoSaveScreenshot : true,
screenshotBaseName : "screenshot",
screenshotTime : true,
}, options);
return r;
},
_parseTransform : function (options) {
var r = sglGetDefaultObject({
matrix : SglMat4.identity(),
rotation : [0.0, 0.0, 0.0],
translation : [0.0, 0.0, 0.0],
scale : [1.0, 1.0, 1,0],
}, options);
// if any of rotation, translation or scale are defined, matrix is overwritten
var overwrite = false;
var matrixT = SglMat4.identity();
var matrixR = SglMat4.identity();
var matrixS = SglMat4.identity();
if((r.translation[0] != 0.0)||(r.translation[1] != 0.0)||(r.translation[2] != 0.0))
{
matrixT = SglMat4.translation(r.translation);
overwrite = true;
}
if((r.rotation[0] != 0.0)||(r.rotation[1] != 0.0)||(r.rotation[2] != 0.0))
{
var mrX = SglMat4.rotationAngleAxis(sglDegToRad(r.rotation[0]), [1.0, 0.0, 0.0]);
var mrY = SglMat4.rotationAngleAxis(sglDegToRad(r.rotation[1]), [0.0, 1.0, 0.0]);
var mrZ = SglMat4.rotationAngleAxis(sglDegToRad(r.rotation[2]), [0.0, 0.0, 1.0]);
matrixR = SglMat4.mul(SglMat4.mul(mrZ, mrY), mrX);
overwrite = true;
}
if((r.scale[0] != 1.0)||(r.scale[1] != 1.0)||(r.scale[2] != 1.0))
{
matrixS = SglMat4.scaling(r.scale);
overwrite = true;
}
if (overwrite)
r.matrix = SglMat4.mul(SglMat4.mul(matrixT, matrixR), matrixS);
return r;
},
//----------------------------------------------------------------------------------------
//SHADERS RELATED FUNCTIONS
//----------------------------------------------------------------------------------------
// standard program for points rendering
_createStandardPointsProgram : function () {
var gl = this.ui.gl;
var pointsVertexShader = new SglVertexShader(gl, "\
precision highp float; \n\
\n\
uniform mat4 uWorldViewProjectionMatrix; \n\
uniform mat3 uViewSpaceNormalMatrix; \n\
uniform mat4 uWorldViewMatrix; \n\
uniform mat4 uModelMatrix; \n\
uniform float uPointSize; \n\
\n\
attribute vec3 aPosition; \n\
attribute vec3 aNormal; \n\
attribute vec4 aColor; \n\
attribute float aPointSize; \n\
\n\
varying vec3 vNormal; \n\
varying vec4 vColor; \n\
varying vec4 vModelPos; \n\
varying vec4 vModelViewPos; \n\
\n\
void main(void) \n\
{ \n\
vNormal = normalize(uViewSpaceNormalMatrix * aNormal); \n\
vColor = aColor; \n\
vModelPos = uModelMatrix * vec4(aPosition, 1.0); \n\
vModelViewPos = uWorldViewMatrix * vec4(aPosition, 1.0); \n\
\n\
gl_Position = uWorldViewProjectionMatrix * vec4(aPosition, 1.0); \n\
gl_PointSize = uPointSize * aPointSize; \n\
} \n\
");
if(this._isDebugging)
console.log("STD POINTS Vertex Shader Log:\n" + pointsVertexShader.log);
var pointsFragmentShader = new SglFragmentShader(gl, "\
#extension GL_EXT_frag_depth : enable \n\
precision highp float; \n\
\n\
uniform vec3 uViewSpaceLightDirection; \n\
uniform float uAlpha; \n\
uniform bool uUseSolidColor; \n\
uniform bool uUseLighting; \n\
uniform vec3 uSolidColor; \n\
uniform vec4 uSpecularColor; \n\
uniform vec3 uClipPoint; \n\
uniform vec3 uClipAxis; \n\
uniform vec4 uClipPlane; \n\
uniform vec3 uClipColor; \n\
uniform float uClipColorSize; \n\
\n\
varying vec3 vNormal; \n\
varying vec4 vColor; \n\
varying vec4 vModelPos; \n\
varying vec4 vModelViewPos; \n\
\n\
void main(void) \n\
{ \n\
if(length(uClipPlane.xyz) > 0.0) \n\
if( dot(vModelPos, uClipPlane) > 0.0) discard; \n\
if(length(uClipAxis) > 0.0) \n\
{ \n\
if( uClipAxis[0] * (vModelPos[0] - uClipPoint[0]) > 0.0) discard; \n\
if( uClipAxis[1] * (vModelPos[1] - uClipPoint[1]) > 0.0) discard; \n\
if( uClipAxis[2] * (vModelPos[2] - uClipPoint[2]) > 0.0) discard; \n\
} \n\
\n\
vec2 cxy = 2.0 * gl_PointCoord - 1.0; \n\
float r = dot(cxy, cxy); \n\
if (r > 1.0) { discard; } \n\
\n\
vec3 renderColor = vec3(1.0, 1.0, 1.0); \n\
vec3 diffuse = vColor.rgb; \n\
float lambert = 1.0; \n\
vec3 specular = vec3(0.0, 0.0, 0.0); \n\
\n\
if(uUseSolidColor) { \n\
if(uSolidColor.r + uSolidColor.g + uSolidColor.b == -3.0) \n\
diffuse = vColor.aaa; \n\
else \n\
diffuse = uSolidColor; \n\
} \n\
\n\
if((uUseLighting)&&(length(vNormal) > 0.0)) \n\
{ \n\
float nDotL = dot(vNormal, -uViewSpaceLightDirection); \n\
lambert = max(0.0, nDotL); \n\
\n\
vec3 halfV = normalize(-uViewSpaceLightDirection -vModelViewPos.xyz);\n\
float spc = pow(max(dot(vNormal, halfV),0.0), uSpecularColor.a); \n\
specular = spc * uSpecularColor.rgb; \n\
} \n\
\n\
renderColor = (diffuse * lambert) + specular; \n\
\n\
if((length(uClipPlane.xyz) > 0.0)&&(uClipColorSize>0.0)) \n\
if( dot(vModelPos, uClipPlane) > -uClipColorSize) renderColor = uClipColor; \n\
if((length(uClipAxis) > 0.0)&&(uClipColorSize>0.0)) \n\
{ \n\
if( uClipAxis[0] * (vModelPos[0] - uClipPoint[0] + (uClipAxis[0]*uClipColorSize)) > 0.0) renderColor = uClipColor; \n\
if( uClipAxis[1] * (vModelPos[1] - uClipPoint[1] + (uClipAxis[1]*uClipColorSize)) > 0.0) renderColor = uClipColor; \n\
if( uClipAxis[2] * (vModelPos[2] - uClipPoint[2] + (uClipAxis[2]*uClipColorSize)) > 0.0) renderColor = uClipColor; \n\
} \n\
\n\
gl_FragColor = vec4(renderColor, uAlpha); \n\
gl_FragDepthEXT = gl_FragCoord.z + 0.0001*(pow(r, 2.0)); \n\
} \n\
");
if(this._isDebugging)
console.log("STD POINTS Fragment Shader Log:\n" + pointsFragmentShader.log);
var program = new SglProgram(gl, {
shaders : [
pointsVertexShader,
pointsFragmentShader
],
attributes : {
"aPosition" : 0,
"aNormal" : 1,
"aColor" : 2,
"aPointSize": 4
},
uniforms : {
"uWorldViewProjectionMatrix" : SglMat4.identity(),
"uViewSpaceNormalMatrix" : SglMat3.identity(),
"uWorldViewMatrix" : SglMat4.identity(),
"uModelMatrix" : SglMat4.identity(),
"uViewSpaceLightDirection" : [0.0, 0.0, -1.0],
"uPointSize" : 1.0,
"uAlpha" : 1.0,
"uUseSolidColor" : false,
"uUseLighting" : true,
"uSolidColor" : [1.0, 1.0, 1.0],
"uSpecularColor" : [0.0, 0.0, 0.0, 32.0],
"uClipPoint" : [0.0, 0.0, 0.0],
"uClipAxis" : [0.0, 0.0, 0.0],
"uClipPlane" : [0.0, 0.0, 0.0, 0.0],
"uClipColor" : [1.0, 1.0, 1.0],
"uClipColorSize" : 0.5
}
});
if(this._isDebugging)
console.log("STD POINTS Program Log:\n" + program.log);
return program;
},
// standard program for faces rendering
_createStandardFacesProgram : function () {
var gl = this.ui.gl;
var facesVertexShader = new SglVertexShader(gl, "\
precision highp float; \n\
\n\
uniform mat4 uWorldViewProjectionMatrix; \n\
uniform mat3 uViewSpaceNormalMatrix; \n\
uniform mat4 uWorldViewMatrix; \n\
uniform mat4 uModelMatrix; \n\
\n\
attribute vec3 aPosition; \n\
attribute vec3 aNormal; \n\
attribute vec4 aColor; \n\
attribute vec2 aTextureCoord; \n\
\n\
varying vec3 vNormal; \n\
varying vec4 vColor; \n\
varying vec4 vModelPos; \n\
varying vec4 vModelViewPos; \n\
varying vec2 vTextureCoord; \n\
\n\
void main(void) \n\
{ \n\
vNormal = normalize(uViewSpaceNormalMatrix * aNormal); \n\
vColor = aColor; \n\
vModelPos = uModelMatrix * vec4(aPosition, 1.0); \n\
vModelViewPos = uWorldViewMatrix * vec4(aPosition, 1.0); \n\
vTextureCoord = aTextureCoord; \n\
\n\
gl_Position = uWorldViewProjectionMatrix * vec4(aPosition, 1.0); \n\
} \n\
");
if(this._isDebugging)
console.log("STD FACES Vertex Shader Log:\n" + facesVertexShader.log);
var facesFragmentShader = new SglFragmentShader(gl, "\
precision highp float; \n\
\n\
uniform vec3 uViewSpaceLightDirection; \n\
uniform float uAlpha; \n\
uniform bool uUseSolidColor; \n\
uniform bool uUseLighting; \n\
uniform vec4 uBackFaceColor; \n\
uniform vec3 uSolidColor; \n\
uniform vec4 uSpecularColor; \n\
uniform vec3 uClipPoint; \n\
uniform vec3 uClipAxis; \n\
uniform vec4 uClipPlane; \n\
uniform vec3 uClipColor; \n\
uniform float uClipColorSize; \n\
uniform sampler2D uSampler; \n\
\n\
varying vec3 vNormal; \n\
varying vec4 vColor; \n\
varying vec4 vModelPos; \n\
varying vec4 vModelViewPos; \n\
varying vec2 vTextureCoord; \n\
\n\
void main(void) \n\
{ \n\
if(length(uClipPlane.xyz) > 0.0) \n\
if( dot(vModelPos, uClipPlane) > 0.0) discard; \n\
if(length(uClipAxis) > 0.0) \n\
{ \n\
if( uClipAxis[0] * (vModelPos[0] - uClipPoint[0]) > 0.0) discard; \n\
if( uClipAxis[1] * (vModelPos[1] - uClipPoint[1]) > 0.0) discard; \n\
if( uClipAxis[2] * (vModelPos[2] - uClipPoint[2]) > 0.0) discard; \n\
} \n\
\n\
vec3 renderColor = vec3(1.0, 1.0, 1.0); \n\
vec3 diffuse = vColor.rgb; \n\
float lambert = 1.0; \n\
vec3 specular = vec3(0.0, 0.0, 0.0); \n\
\n\
if(vTextureCoord.x != 0.0) \n\
diffuse = texture2D(uSampler, vTextureCoord).xyz; \n\
\n\
if(uUseSolidColor) { \n\
if(uSolidColor.r + uSolidColor.g + uSolidColor.b == -3.0) \n\
diffuse = vColor.aaa; \n\
else if(uSolidColor.r + uSolidColor.g + uSolidColor.b == -6.0) \n\
diffuse = vColor.rgb; \n\
else \n\
diffuse = uSolidColor; \n\
} \n\
\n\
if((uUseLighting)&&(length(vNormal) > 0.0)) \n\
{ \n\
float nDotL = dot(vNormal, -uViewSpaceLightDirection); \n\
lambert = max(0.0, gl_FrontFacing? nDotL : -nDotL); \n\
\n\
vec3 halfV = normalize(-uViewSpaceLightDirection -vModelViewPos.xyz);\n\
float spc = pow(max(dot(vNormal, halfV),0.0), uSpecularColor.a); \n\
specular = spc * uSpecularColor.rgb; \n\
} \n\
\n\
renderColor = (diffuse * lambert) + specular; \n\
if(gl_FrontFacing==false) \n\
{ \n\
if (uBackFaceColor[3]==0.0) renderColor = renderColor * uBackFaceColor.rgb; \n\
else if(uBackFaceColor[3]==1.0) renderColor = uBackFaceColor.rgb; \n\
else if(uBackFaceColor[3]==2.0) discard; \n\
else if(uBackFaceColor[3]==3.0) renderColor = (uBackFaceColor.rgb * lambert)+specular;\n\
} \n\
\n\
if((length(uClipPlane.xyz) > 0.0)&&(uClipColorSize>0.0)) \n\
if( dot(vModelPos, uClipPlane) > -uClipColorSize) renderColor = uClipColor; \n\
if((length(uClipAxis) > 0.0)&&(uClipColorSize>0.0)) \n\
{ \n\
if( uClipAxis[0] * (vModelPos[0] - uClipPoint[0] + (uClipAxis[0]*uClipColorSize)) > 0.0) renderColor = uClipColor; \n\
if( uClipAxis[1] * (vModelPos[1] - uClipPoint[1] + (uClipAxis[1]*uClipColorSize)) > 0.0) renderColor = uClipColor; \n\
if( uClipAxis[2] * (vModelPos[2] - uClipPoint[2] + (uClipAxis[2]*uClipColorSize)) > 0.0) renderColor = uClipColor; \n\
} \n\
\n\
gl_FragColor = vec4(renderColor, uAlpha); \n\
} \n\
");
if(this._isDebugging)
console.log("STD FACES Fragment Shader Log:\n" + facesFragmentShader.log);
var program = new SglProgram(gl, {
shaders : [
facesVertexShader,
facesFragmentShader
],
attributes : {
"aPosition" : 0,
"aNormal" : 1,
"aColor" : 2,
"aTextureCoord" : 3
},
uniforms : {
"uWorldViewProjectionMatrix" : SglMat4.identity(),
"uViewSpaceNormalMatrix" : SglMat3.identity(),
"uWorldViewMatrix" : SglMat4.identity(),
"uModelMatrix" : SglMat4.identity(),
"uViewSpaceLightDirection" : [0.0, 0.0, -1.0],
"uAlpha" : 1.0,
"uUseSolidColor" : false,
"uUseLighting" : true,
"uBackFaceColor" : [0.4, 0.3, 0.3, 0.0],
"uSolidColor" : [1.0, 1.0, 1.0],
"uSpecularColor" : [0.0, 0.0, 0.0, 32.0],
"uClipPoint" : [0.0, 0.0, 0.0],
"uClipAxis" : [0.0, 0.0, 0.0],
"uClipPlane" : [0.0, 0.0, 0.0, 0.0],
"uClipColor" : [1.0, 1.0, 1.0],
"uClipColorSize" : 0.5,
"uSampler" : 0
}
});
if(this._isDebugging)
console.log("STD FACE Program Log:\n" + program.log);
return program;
},
// utils program for XYZ picking and color coded rendering
_createUtilsProgram : function () {
var gl = this.ui.gl;
var utilsVertexShader = new SglVertexShader(gl, "\
precision highp float; \n\
\n\
uniform mat4 uWorldViewProjectionMatrix; \n\
uniform mat4 uModelMatrix; \n\
uniform float uPointSize; \n\
\n\
attribute vec3 aPosition; \n\
attribute vec3 aNormal; \n\
attribute vec4 aColor; \n\
attribute float aPointSize; \n\
\n\
varying vec4 vModelPos; \n\
\n\
void main(void) \n\
{ \n\
vModelPos = uModelMatrix * vec4(aPosition, 1.0); \n\
gl_Position = uWorldViewProjectionMatrix * vec4(aPosition, 1.0); \n\
gl_PointSize = uPointSize * aPointSize; \n\
} \n\
");
if(this._isDebugging)
console.log("UTILS Vertex Shader Log:\n" + utilsVertexShader.log);
var utilsFragmentShader = new SglFragmentShader(gl, "\
precision highp float; \n\
\n\
uniform vec3 uClipPoint; \n\
uniform vec3 uClipAxis; \n\
uniform vec4 uClipPlane; \n\
uniform vec4 uBackFaceColor; \n\
uniform vec4 uColorID; \n\
uniform float uMode; \n\
\n\
varying vec4 vModelPos; \n\
\n\
vec4 pack_depth(const in float depth) \n\
{ \n\
const vec4 bit_shift = vec4(255.0*255.0*255.0, 255.0*255.0, 255.0, 1.0); \n\
const vec4 bit_mask = vec4(0.0, 1.0/255.0, 1.0/255.0, 1.0/255.0); \n\
vec4 res = fract(depth * bit_shift); \n\
res -= res.xxyz * bit_mask; \n\
return res; \n\
} \n\
\n\
void main(void) \n\
{ \n\
if(length(uClipPlane.xyz) > 0.0) \n\
if( dot(vModelPos, uClipPlane) > 0.0) discard; \n\
if(length(uClipAxis) > 0.0) \n\
{ \n\
if( uClipAxis[0] * (vModelPos[0] - uClipPoint[0]) > 0.0) discard; \n\
if( uClipAxis[1] * (vModelPos[1] - uClipPoint[1]) > 0.0) discard; \n\
if( uClipAxis[2] * (vModelPos[2] - uClipPoint[2]) > 0.0) discard; \n\
} \n\
if((gl_FrontFacing==false) && (uBackFaceColor[3]==2.0)) discard; \n\
\n\
vec4 outColor; \n\
if(uMode == 1.0) //xyx picking \n\
outColor = pack_depth(gl_FragCoord.z); \n\
else if(uMode == 2.0) //color coded \n\
outColor = uColorID; \n\
\n\
gl_FragColor = outColor; \n\
} \n\
");
if(this._isDebugging)
console.log("UTILS Fragment Shader Log:\n" + utilsFragmentShader.log);
var utilsProgram = new SglProgram(gl, {
shaders : [
utilsVertexShader,
utilsFragmentShader
],
attributes : {
"aPosition" : 0,
"aNormal" : 1,
"aColor" : 2,
"aPointSize": 4
},
uniforms : {
"uWorldViewProjectionMatrix" : SglMat4.identity(),
"uModelMatrix" : SglMat4.identity(),
"uClipPoint" : [0.0, 0.0, 0.0],
"uClipAxis" : [0.0, 0.0, 0.0],
"uClipPlane" : [0.0, 0.0, 0.0, 0.0],
"uBackFaceColor" : [0.4, 0.3, 0.3, 0.0],
"uColorID" : [1.0, 0.5, 0.0, 1.0],
"uPointSize" : 1.0,
"uMode" : 1.0
}
});
if(this._isDebugging)
console.log("UTILS Program Log:\n" + utilsProgram.log);
return utilsProgram;
},
// single-color barely-shaded program for spot and planes rendering
_createColorShadedProgram : function () {
var gl = this.ui.gl;
var colorShadedVertexShader = new SglVertexShader(gl, "\
precision highp float; \n\
\n\
uniform mat4 uWorldViewProjectionMatrix; \n\
uniform mat3 uViewSpaceNormalMatrix; \n\
uniform float uPointSize; \n\
\n\
attribute vec3 aPosition; \n\
attribute vec3 aNormal; \n\
attribute float aPointSize; \n\
\n\
varying vec3 vNormal; \n\
\n\
void main(void) \n\
{ \n\
vNormal = uViewSpaceNormalMatrix * aNormal; \n\
\n\
gl_Position = uWorldViewProjectionMatrix * vec4(aPosition, 1.0); \n\
gl_PointSize = uPointSize * aPointSize; \n\
} \n\
");
if(this._isDebugging)
console.log("COLOR SHADED Vertex Shader Log:\n" + colorShadedVertexShader.log);
var colorShadedFragmentShader = new SglFragmentShader(gl, "\
precision highp float; \n\
\n\
uniform vec3 uViewSpaceLightDirection; \n\
uniform vec4 uColorID; \n\
\n\
varying vec3 vNormal; \n\
\n\
void main(void) \n\
{ \n\
if(uColorID[3] == 0.0) discard; \n\
vec3 diffuse = vec3(uColorID[0], uColorID[1], uColorID[2]); \n\
\n\
if(vNormal[0] != 0.0 || vNormal[1] != 0.0 || vNormal[2] != 0.0) { \n\
vec3 normal = normalize(vNormal); \n\
float nDotL = dot(normal, -uViewSpaceLightDirection); \n\
float lambert = max(-nDotL, nDotL); \n\
\n\
diffuse = (diffuse * 0.5) + (diffuse * lambert * 0.5); \n\
} \n\
gl_FragColor = vec4(diffuse, uColorID[3]); \n\
} \n\
");
if(this._isDebugging)
console.log("COLOR SHADED Fragment Shader Log:\n" + colorShadedFragmentShader.log);
var program = new SglProgram(gl, {
shaders : [
colorShadedVertexShader,
colorShadedFragmentShader
],
attributes : {
"aPosition" : 0,
"aNormal" : 1,
"aPointSize": 4
},
uniforms : {
"uWorldViewProjectionMatrix" : SglMat4.identity(),
"uViewSpaceNormalMatrix" : SglMat3.identity(),
"uViewSpaceLightDirection" : [0.0, 0.0, -1.0],
"uColorID" : [1.0, 0.5, 0.0, 1.0],
"uPointSize" : 1.0
}
});
if(this._isDebugging)
console.log("COLOR SHADED Program Log:\n" + program.log);
return program;
},
// standard technique for PLY points rendering
_createStandardPointsTechnique : function () {
var gl = this.ui.gl;
var technique = new SglTechnique(gl, {
program : this._createStandardPointsProgram(),
vertexStreams : {
"aNormal" : [ 0.0, 0.0, 0.0 ],
"aColor" : [ 0.8, 0.8, 0.8, 1.0 ],
"aPointSize" : 1.0
},
globals : {
"uWorldViewProjectionMatrix" : { semantic : "uWorldViewProjectionMatrix", value : SglMat4.identity() },
"uViewSpaceNormalMatrix" : { semantic : "uViewSpaceNormalMatrix", value : SglMat3.identity() },
"uWorldViewMatrix" : { semantic : "uWorldViewMatrix", value : SglMat4.identity() },
"uModelMatrix" : { semantic : "uModelMatrix", value : SglMat4.identity() },
"uViewSpaceLightDirection" : { semantic : "uViewSpaceLightDirection", value : [ 0.0, 0.0, -1.0 ] },
"uPointSize" : { semantic : "uPointSize", value : 1.0 },
"uAlpha" : { semantic : "uAlpha", value : 1.0 },
"uUseSolidColor" : { semantic : "uUseSolidColor", value : false },
"uUseLighting" : { semantic : "uUseLighting", value : true },
"uSolidColor" : { semantic : "uSolidColor", value : [ 1.0, 1.0, 1.0 ] },
"uBackFaceColor" : { semantic : "uBackFaceColor", value : [0.4, 0.3, 0.3, 0.0] },
"uSpecularColor" : { semantic : "uSpecularColor", value : [0.5, 0.2, 0.8, 32.0] },
"uClipPoint" : { semantic : "uClipPoint", value : [ 0.0, 0.0, 0.0 ] },
"uClipAxis" : { semantic : "uClipAxis", value : [ 0.0, 0.0, 0.0 ] },
"uClipPlane" : { semantic : "uClipPlane", value : [ 0.0, 0.0, 0.0, 0.0 ] },
"uClipColor" : { semantic : "uClipColor", value : [ 1.0, 1.0, 1.0 ]},
"uClipColorSize" : { semantic : "uClipColorSize", value : 0.5 }
}
});
return technique;
},
// standard technique for PLY faces rendering
_createStandardFacesTechnique : function () {
var gl = this.ui.gl;
var technique = new SglTechnique(gl, {
program : this._createStandardFacesProgram(),
vertexStreams : {
"aNormal" : [ 0.0, 0.0, 0.0 ],
"aColor" : [ 0.8, 0.8, 0.8, 1.0 ],
"aTextureCoord" : [ 0.0, 0.0 ]
},
globals : {
"uWorldViewProjectionMatrix" : { semantic : "uWorldViewProjectionMatrix", value : SglMat4.identity() },
"uViewSpaceNormalMatrix" : { semantic : "uViewSpaceNormalMatrix", value : SglMat3.identity() },
"uWorldViewMatrix" : { semantic : "uWorldViewMatrix", value : SglMat4.identity() },
"uModelMatrix" : { semantic : "uModelMatrix", value : SglMat4.identity() },
"uViewSpaceLightDirection" : { semantic : "uViewSpaceLightDirection", value : [ 0.0, 0.0, -1.0 ] },
"uAlpha" : { semantic : "uAlpha", value : 1.0 },
"uUseSolidColor" : { semantic : "uUseSolidColor", value : false },
"uUseLighting" : { semantic : "uUseLighting", value : true },
"uSolidColor" : { semantic : "uSolidColor", value : [ 1.0, 1.0, 1.0 ] },
"uBackFaceColor" : { semantic : "uBackFaceColor", value : [0.4, 0.3, 0.3, 0.0] },
"uSpecularColor" : { semantic : "uSpecularColor", value : [0.5, 0.2, 0.8, 32.0] },
"uClipPoint" : { semantic : "uClipPoint", value : [ 0.0, 0.0, 0.0 ] },
"uClipAxis" : { semantic : "uClipAxis", value : [ 0.0, 0.0, 0.0 ] },
"uClipPlane" : { semantic : "uClipPlane", value : [ 0.0, 0.0, 0.0, 0.0 ] },
"uClipColor" : { semantic : "uClipColor", value : [ 1.0, 1.0, 1.0 ]},
"uClipColorSize" : { semantic : "uClipColorSize", value : 0.5 },
"uSampler" : { semantic : "uSampler", value : 0 }
}
});
return technique;
},
// utils technique for PLY picking and color coded rendering
_createUtilsTechnique : function () {
var gl = this.ui.gl;
var technique = new SglTechnique(gl, {
program : this._createUtilsProgram(),
vertexStreams : {
"aNormal" : [ 0.0, 0.0, 0.0 ],
"aColor" : [ 0.8, 0.8, 0.8, 1.0 ],
"aPointSize" : 1.0,
},
globals : {
"uWorldViewProjectionMatrix" : { semantic : "uWorldViewProjectionMatrix", value : SglMat4.identity() },
"uModelMatrix" : { semantic : "uModelMatrix", value : SglMat4.identity() },
"uClipPoint" : { semantic : "uClipPoint", value : [ 0.0, 0.0, 0.0 ] },
"uClipAxis" : { semantic : "uClipAxis", value : [ 0.0, 0.0, 0.0 ] },
"uClipPlane" : { semantic : "uClipPlane", value : [ 0.0, 0.0, 0.0, 0.0 ] },
"uBackFaceColor" : { semantic : "uBackFaceColor", value : [0.4, 0.3, 0.3, 0.0] },
"uColorID" : { semantic : "uColorID", value : [1.0, 0.5, 0.0, 1.0] },
"uPointSize" : { semantic : "uPointSize", value : 1.0 },
"uMode" : { semantic : "uMode", value : 1.0 }
}
});
return technique;
},
// single-color barely-shaded technique for PLY spot and planes rendering
_createColorShadedTechnique : function () {
var gl = this.ui.gl;
var technique = new SglTechnique(gl, {
program : this._createColorShadedProgram(),
vertexStreams : {
"aNormal" : [ 0.0, 0.0, 0.0 ],
"aPointSize" : 1.0
},
globals : {
"uWorldViewProjectionMatrix" : { semantic : "uWorldViewProjectionMatrix", value : SglMat4.identity() },
"uViewSpaceNormalMatrix" : { semantic : "uViewSpaceNormalMatrix", value : SglMat3.identity() },
"uViewSpaceLightDirection" : { semantic : "uViewSpaceLightDirection", value : [ 0.0, 0.0, -1.0 ] },
"uColorID" : { semantic : "uColorID", value : [1.0, 0.5, 0.25, 1.0] },
"uPointSize" : { semantic : "uPointSize", value : 1.0 }
}
});
return technique;
},
// 2 points line rendering
_createSimpleLinetechnique : function () {
var gl = this.ui.gl;
var technique = new SglTechnique(gl, {
vertexShader : "\
precision highp float; \n\
\n\
uniform mat4 uWorldViewProjectionMatrix; \n\
uniform vec3 uPointA; \n\
uniform vec3 uPointB; \n\
\n\
attribute vec3 aPosition; \n\
attribute vec3 aNormal; \n\
attribute vec4 aColor; \n\
\n\
void main(void) \n\
{ \n\
vec3 newPos; \n\
if(aPosition[0]==0.0) \n\
newPos = uPointA; \n\
else \n\
newPos = uPointB; \n\
gl_Position = uWorldViewProjectionMatrix * vec4(newPos, 1.0); \n\
gl_PointSize = 8.0; \n\
} \n\
",
fragmentShader : "\
precision highp float; \n\
\n\
uniform vec4 uLineColor; \n\
\n\
void main(void) \n\
{ \n\
gl_FragColor = uLineColor; \n\
} \n\
",
vertexStreams : {
"aNormal" : [ 0.0, 0.0, 0.0 ],
"aColor" : [ 0.8, 0.8, 0.8, 1.0 ]
},
globals : {
"uWorldViewProjectionMatrix" : { semantic : "uWorldViewProjectionMatrix", value : SglMat4.identity() },
"uLineColor" : { semantic : "uLineColor", value : [0.0, 1.0, 0.5, 1.0] },
"uPointA" : { semantic : "uPointA", value : [0.0, 0.0, 0.0] },
"uPointB" : { semantic : "uPointB", value : [1.0, 1.0, 1.0] }
}
});
return technique;
},
// multiple lines/points rendering
_createMultiLinesPointstechnique : function () {
var gl = this.ui.gl;
var technique = new SglTechnique(gl, {
vertexShader : "\
precision highp float; \n\
\n\
uniform mat4 uWorldViewProjectionMatrix; \n\
uniform float uPointSize; \n\
\n\
attribute vec3 aPosition; \n\
attribute vec3 aNormal; \n\
attribute vec4 aColor; \n\
\n\
varying vec3 vNormal; \n\
varying vec4 vColor; \n\
\n\
void main(void) \n\
{ \n\
vColor = aColor; \n\
gl_Position = uWorldViewProjectionMatrix * vec4(aPosition, 1.0); \n\
gl_PointSize = uPointSize; \n\
} \n\
",
fragmentShader : "\
#extension GL_EXT_frag_depth : enable \n\
precision highp float; \n\
\n\
uniform vec4 uColorID; \n\
uniform float uZOff; \n\
\n\
varying vec4 vColor; \n\
\n\
void main(void) \n\
{ \n\
gl_FragColor = uColorID; \n\
gl_FragDepthEXT = gl_FragCoord.z - uZOff; \n\
} \n\
",
vertexStreams : {
"aNormal" : [ 0.0, 0.0, 0.0 ],
"aColor" : [ 0.8, 0.8, 0.8, 1.0 ]
},
globals : {
"uWorldViewProjectionMatrix" : { semantic : "uWorldViewProjectionMatrix", value : SglMat4.identity() },
"uColorID" : { semantic : "uColorID", value : [1.0, 0.5, 0.25, 1.0] },
"uPointSize" : { semantic : "uPointSize", value : 1.0 },
"uZOff" : { semantic : "uZOff", value : 0.0 },
}
});
return technique;
},
//----------------------------------------------------------------------------------------
// SUPPORT FUNCTIONS
//----------------------------------------------------------------------------------------
_onMeshReady : function () {
this._objectLoaded();
},
_onTextureReady : function () {
this._objectLoaded();
},
_onBackgroundReady : function () {
this._objectLoaded();
},
_objectLoaded : function () {
this._objectsToLoad--;
this._testReady();
},
_testReady : function () {
if (this._objectsToLoad != 0) return;
this._sceneReady = this._scenePrepare();
this.repaint();
},
_scenePrepare : function () {
var meshes = this._scene.meshes;
var instances = this._scene.modelInstances;
var spots = this._scene.spots;
for (var mesh in meshes) {
if (!meshes[mesh].renderable) continue;
for (var inst in instances)
if (mesh == instances[inst].mesh)
instances[inst].rendermode = meshes[mesh].renderable.renderMode[0];
for (var spt in spots)
if (mesh == spots[spt].mesh)
spots[spt].rendermode = meshes[mesh].renderable.renderMode[0];
}
return true;
},
_isSceneReady : function () {
var r = (this._scene && this._sceneParsed && this._sceneReady);
return r;
},
_pickingRefresh: function(x,y) {
this._pickpoint[0] = x;
this._pickpoint[1] = y;
var pickedPixel;
var ID, cursor;
if(this._onEndPickingPoint||this._onEndMeasurement||this._onPickedSpot||this._onEnterSpot||this._onLeaveSpot){
pickedPixel = this._drawScenePickingSpots();
ID = this._Color2ID(pickedPixel);
if(this._lastSpotID != ID){
var spots = this._scene.spots;
if(ID != 0){
for (var spt in spots) {
if (spots[spt].ID == ID) {
this._pickedSpot = spt;
if(this._onHover){
cursor = spots[spt].cursor;
if(/*!this._movingLight ||*/ !this._isMeasuring){
this._lastCursor = document.getElementById(this.ui.canvas.id).style.cursor;
document.getElementById(this.ui.canvas.id).style.cursor = cursor;
}
if(this._onLeaveSpot && this._lastPickedSpot!=null) this._onLeaveSpot(this._lastPickedSpot);
if(this._onEnterSpot && this._pickedSpot!=null) this._onEnterSpot(this._pickedSpot);
this.repaint();
}
this._lastPickedSpot = spt;
break;
}
}
this._lastSpotID = ID;
}
else{
this._pickedSpot = null;
if(this._onHover){
if(/*!this._movingLight ||*/ !this._isMeasuring) document.getElementById(this.ui.canvas.id).style.cursor = "default";
if(this._onLeaveSpot && this._lastPickedSpot!=null) this._onLeaveSpot(this._lastPickedSpot);
//if(this._onEnterSpot) this._onEnterSpot(this._pickedSpot);
this._lastPickedSpot = null;
this.repaint();
}
this._lastSpotID = ID;
}
}
}
if(this._onEndPickingPoint||this._onEndMeasurement||this._onPickedInstance||this._onEnterInstance||this._onLeaveInstance){
pickedPixel = this._drawScenePickingInstances();
ID = this._Color2ID(pickedPixel);
if(this._lastInstanceID == ID && !(this._onPickedSpot||this._onEnterSpot||this._onLeaveSpot)) return;
if(ID != 0){
var instances = this._scene.modelInstances;
for (var inst in instances) {
if (instances[inst].ID == ID) {
this._pickedInstance = inst;
if(this._onHover){
cursor = instances[inst].cursor;
if(/*!this._movingLight ||*/ !this._isMeasuring){
this._lastCursor = cursor;
if(this._pickedSpot==null)document.getElementById(this.ui.canvas.id).style.cursor = cursor;
this.repaint();
}
if(this._onLeaveInstance && this._lastPickedInstance!=null) this._onLeaveInstance(this._lastPickedInstance);
if(this._onEnterInstance && this._pickedInstance!=null) this._onEnterInstance(this._pickedInstance);
}
this._lastPickedInstance = inst;
break;
}
}
}
else{
this._pickedInstance = null;
if(this._onHover){
this._lastCursor = "default";
if((/*!this._movingLight ||*/ !this._isMeasuring) && this._pickedSpot==null) document.getElementById(this.ui.canvas.id).style.cursor = "default";
if(this._onLeaveInstance && this._lastPickedInstance!=null) this._onLeaveInstance(this._lastPickedInstance);
//if(this._onEnterInstance) this._onEnterInstance(this._pickedInstance);
this.repaint();
}
this._lastPickedInstance = null;
}
this._lastInstanceID = ID;
}
},
_measureRefresh : function (button, x, y, e) {
// if(e.target.id!=this.ui.gl.canvas.id) return;
if(this._isMeasuringDistance){
this._pickpoint[0] = x;
this._pickpoint[1] = y;
var ppoint = this._drawScenePickingXYZ();
if ((ppoint!=null)&&(this._measurementStage != 2)) {
this._pointA = ppoint;
this._measurementStage=2;
this.repaint();
}
else if ((ppoint!=null)&&(this._measurementStage == 2)) {
this._pointB = ppoint;
this.measurement = SglVec3.length(SglVec3.sub(this._pointA, this._pointB));
this._measurementStage=3;
this.repaint();
if(this._onEndMeasurement)
this._onEndMeasurement(this.measurement, [this._pointA[0], this._pointA[1], this._pointA[2]], [this._pointB[0], this._pointB[1], this._pointB[2]]);
}
}
},
_startMeasurement : function () {
if (this._isMeasuringDistance) return;
this._isMeasuring = this._isMeasuringDistance = true;
this._measurementStage = 1; // 0=inactive 1=picking pointA 2=picking pointB 3=measurement ready
this._pointA = [0.0, 0.0, 0.0];
this._pointB = [0.0, 0.0, 0.0];
this.measurement = 0.0;
this.repaint();
},
_stopMeasurement : function () {
this._isMeasuringDistance = false;
if (!this._isMeasuringPickpoint) this._isMeasuring = this._isMeasuringDistance;
this._measurementStage = 0; // 0=inactive 1=picking pointA 2=picking pointB 3=measurement ready
this._pointA = [0.0, 0.0, 0.0];
this._pointB = [0.0, 0.0, 0.0];
this.measurement = 0.0;
this.repaint();
},
_pickpointRefresh : function (button, x, y, e) {
// if(e.target.id!=this.ui.gl.canvas.id) return;
if(this._isMeasuringPickpoint){
this._pickpoint[0] = x;
this._pickpoint[1] = y;
var ppoint = this._drawScenePickingXYZ();
if (ppoint!=null)
{
this._pickedPoint = ppoint;
this._pickValid = true;
if(this._onEndPickingPoint) this._onEndPickingPoint([this._pickedPoint[0], this._pickedPoint[1], this._pickedPoint[2]]);
this.repaint();
}
}
},
_startPickPoint : function () {
if (this._isMeasuringPickpoint) return;
this._isMeasuring = this._isMeasuringPickpoint = true;
this._pickValid = false;
this._pickedPoint = [0.0, 0.0, 0.0];
this.repaint();
},
_stopPickPoint : function () {
this._isMeasuringPickpoint = false;
if (!this._isMeasuringDistance) this._isMeasuring = this._isMeasuringPickpoint;
this._pickValid = false;
this._pickedPoint = [0.0, 0.0, 0.0];
this.repaint();
},
//----------------------------------------------------------------------------------------
// DRAWING SUPPORT FUNCTIONS
//----------------------------------------------------------------------------------------
_setSceneCenterRadius : function () {
var meshes = this._scene.meshes;
var instances = this._scene.modelInstances;
this.sceneCenter = [0.0, 0.0, 0.0];
this.sceneRadiusInv = 1.0;
if(this._scene.space.centerMode == "explicit")
{
this.sceneCenter = this._scene.space.explicitCenter;
}
else if(this._scene.space.centerMode == "specific" && this._scene.space.whichInstanceCenter != "")
{
var mesh = meshes[instances[this._scene.space.whichInstanceCenter].mesh];
if((mesh)&&(mesh.renderable)){
var instCenter = SglVec3.to4(mesh.renderable.datasetCenter,1);
instCenter = SglMat4.mul4(mesh.transform.matrix, instCenter);
instCenter = SglMat4.mul4(instances[this._scene.space.whichInstanceCenter].transform.matrix, instCenter);
instCenter = SglMat4.mul4(this._scene.space.transform.matrix, instCenter);
instCenter = SglVec4.to3(instCenter);
this.sceneCenter = instCenter;
}
}
else if(this._scene.space.centerMode == "scene")
{
var smin = SglVec3.maxNumber();
var smax = SglVec3.minNumber();
var imin = [0.0, 0.0, 0.0];
var imax = [0.0, 0.0, 0.0];
for (var inst in instances) {
var mesh = meshes[instances[inst].mesh];
if((mesh)&&(mesh.renderable)){
var instCenter = SglVec3.to4(mesh.renderable.datasetCenter,1);
instCenter = SglMat4.mul4(mesh.transform.matrix, instCenter);
instCenter = SglMat4.mul4(instances[inst].transform.matrix, instCenter);
instCenter = SglMat4.mul4(this._scene.space.transform.matrix, instCenter);
instCenter = SglVec4.to3(instCenter);
var radius = mesh.renderable.datasetRadius;
var vector111 = SglVec3.one();
vector111 = SglMat3.mul3(SglMat4.to33(mesh.transform.matrix), vector111);
vector111 = SglMat3.mul3(SglMat4.to33(instances[inst].transform.matrix), vector111);
vector111 = SglMat3.mul3(SglMat4.to33(this._scene.space.transform.matrix), vector111);
var scalefactor = SglVec3.length(vector111) / SglVec3.length([1,1,1]);
radius = radius*scalefactor;
imin[0] = instCenter[0] - radius;
imin[1] = instCenter[1] - radius;
imin[2] = instCenter[2] - radius;
imax[0] = instCenter[0] + radius;
imax[1] = instCenter[1] + radius;
imax[2] = instCenter[2] + radius;
if(imin[0] < smin[0]) smin[0] = imin[0];
if(imin[1] < smin[1]) smin[1] = imin[1];
if(imin[2] < smin[2]) smin[2] = imin[2];
if(imax[0] > smax[0]) smax[0] = imax[0];
if(imax[1] > smax[1]) smax[1] = imax[1];
if(imax[2] > smax[2]) smax[2] = imax[2];
}
}
this.sceneCenter = [ (smax[0] + smin[0])/2.0, (smax[1] + smin[1])/2.0, (smax[2] + smin[2])/2.0 ];
}
else //if(this._scene.space.centerMode == "first")
{
for (var inst in instances) {
var mesh = meshes[instances[inst].mesh];
if((mesh)&&(mesh.renderable)){
var instCenter = SglVec3.to4(mesh.renderable.datasetCenter,1);
instCenter = SglMat4.mul4(mesh.transform.matrix, instCenter);
instCenter = SglMat4.mul4(instances[inst].transform.matrix, instCenter);
instCenter = SglMat4.mul4(this._scene.space.transform.matrix, instCenter);
instCenter = SglVec4.to3(instCenter);
this.sceneCenter = instCenter;
break;
}
}
}
if(this._scene.space.radiusMode == "explicit")
{
this.sceneRadiusInv = 1.0 / this._scene.space.explicitRadius;
}
else if(this._scene.space.radiusMode == "specific" && this._scene.space.whichInstanceRadius != "")
{
var mesh = meshes[instances[this._scene.space.whichInstanceRadius].mesh];
if((mesh)&&(mesh.renderable)){
var radius = mesh.renderable.datasetRadius;
var vector111 = SglVec3.one();
vector111 = SglMat3.mul3(SglMat4.to33(mesh.transform.matrix), vector111);
vector111 = SglMat3.mul3(SglMat4.to33(instances[this._scene.space.whichInstanceRadius].transform.matrix), vector111);
vector111 = SglMat3.mul3(SglMat4.to33(this._scene.space.transform.matrix), vector111);
var scalefactor = SglVec3.length(vector111) / SglVec3.length([1,1,1]);
this.sceneRadiusInv = 1.0 / (radius*scalefactor);
}
}
else if(this._scene.space.radiusMode == "scene")
{
var smin = SglVec3.maxNumber();
var smax = SglVec3.minNumber();
var imin = [0.0, 0.0, 0.0];
var imax = [0.0, 0.0, 0.0];
for (var inst in instances) {
var mesh = meshes[instances[inst].mesh];
if((mesh)&&(mesh.renderable)){
var instCenter = SglVec3.to4(mesh.renderable.datasetCenter,1);
instCenter = SglMat4.mul4(mesh.transform.matrix, instCenter);
instCenter = SglMat4.mul4(instances[inst].transform.matrix, instCenter);
instCenter = SglMat4.mul4(this._scene.space.transform.matrix, instCenter);
instCenter = SglVec4.to3(instCenter);
var radius = mesh.renderable.datasetRadius;
var vector111 = SglVec3.one();
vector111 = SglMat3.mul3(SglMat4.to33(mesh.transform.matrix), vector111);
vector111 = SglMat3.mul3(SglMat4.to33(instances[inst].transform.matrix), vector111);
vector111 = SglMat3.mul3(SglMat4.to33(this._scene.space.transform.matrix), vector111);
var scalefactor = SglVec3.length(vector111) / SglVec3.length([1,1,1]);
radius = radius*scalefactor;
imin[0] = instCenter[0] - radius;
imin[1] = instCenter[1] - radius;
imin[2] = instCenter[2] - radius;
imax[0] = instCenter[0] + radius;
imax[1] = instCenter[1] + radius;
imax[2] = instCenter[2] + radius;
if(imin[0] < smin[0]) smin[0] = imin[0];
if(imin[1] < smin[1]) smin[1] = imin[1];
if(imin[2] < smin[2]) smin[2] = imin[2];
if(imax[0] > smax[0]) smax[0] = imax[0];
if(imax[1] > smax[1]) smax[1] = imax[1];
if(imax[2] > smax[2]) smax[2] = imax[2];
}
}
var scenter = [ (smax[0] + smin[0])/2.0, (smax[1] + smin[1])/2.0, (smax[2] + smin[2])/2.0 ]
this.sceneRadiusInv = 1.0 / SglVec3.length(SglVec3.sub(smax, scenter));
}
else //if(this._scene.space.radiusMode == "first")
{
for (var inst in instances) {
var mesh = meshes[instances[inst].mesh];
if((mesh)&&(mesh.renderable)){
var radius = mesh.renderable.datasetRadius;
var vector111 = SglVec3.one();
vector111 = SglMat3.mul3(SglMat4.to33(mesh.transform.matrix), vector111);
vector111 = SglMat3.mul3(SglMat4.to33(instances[inst].transform.matrix), vector111);
vector111 = SglMat3.mul3(SglMat4.to33(this._scene.space.transform.matrix), vector111);
var scalefactor = SglVec3.length(vector111) / SglVec3.length([1,1,1]);
this.sceneRadiusInv = 1.0 / (radius*scalefactor);
break;
}
}
}
},
_destroyPickFramebuffer : function () {
if (this.pickFramebuffer) {
this.pickFramebuffer.destroy();
this.pickFramebuffer = null;
}
if (this.pickColorTexture) {
this.pickColorTexture.destroy();
this.pickColorTexture = null;
}
if (this.pickDepthRenderbuffer) {
this.pickDepthRenderbuffer.destroy();
this.pickDepthRenderbuffer = null;
}
},
_createPickFramebuffer : function (width, height) {
if (this.pickFramebuffer && (this.pickFramebuffer.width == width) && (this.pickFramebuffer.height == height))
return;
else
this._destroyPickFramebuffer();
var gl = this.ui.gl;
this.pickColorTexture = new SglTexture2D(gl, {
internalFormat : gl.RGBA,
width : width,
height : height
});
this.pickDepthRenderbuffer = new SglRenderbuffer(gl, {
internalFormat : gl.DEPTH_COMPONENT16,
width : width,
height : height
});
this.pickFramebuffer = new SglFramebuffer(gl, {
color : this.pickColorTexture,
depth : this.pickDepthRenderbuffer,
autoViewport : true
});
},
_setupDraw : function () {
var width = this.ui.width;
var height = this.ui.height;
var xform = this.xform;
var space = this._scene.space;
this.ui.gl.viewport(0, 0, width, height);
var FOV = space.cameraFOV;
var nearP = space.cameraNearFar[0];
var farP = space.cameraNearFar[1];
// getting scale/center for scene
this._setSceneCenterRadius();
xform.projection.loadIdentity();
if(space.cameraType == "orthographic")
{
//default camera distance in orthographic view is "as large as scene size"
// then, if the trackball is able to provide a better value, we use it
var cDistance = 1.0;
if(typeof this.trackball.distance != "undefined")
cDistance = this.trackball.distance;
var a = cDistance * SpiderGL.Math.tan(sglDegToRad(FOV) / 2);
var b = a * width/height;
xform.projection.ortho([-b, -a, nearP], [b, a, farP]);
}
else
{
xform.projection.perspective(sglDegToRad(FOV), width/height, nearP, farP);
}
xform.view.loadIdentity();
xform.view.lookAt([0.0, 0.0, 0.0], [0.0, 0.0, -1.0], [0.0, 1.0, 0.0]);
this.viewMatrix = xform.viewMatrix;
xform.model.loadIdentity();
xform.model.multiply(this.trackball.matrix);
// scale to unit box + recenter
xform.model.scale([this.sceneRadiusInv, this.sceneRadiusInv, this.sceneRadiusInv]);
xform.model.translate(SglVec3.neg(this.sceneCenter));
Nexus.beginFrame(this.ui.gl, this.ui.framesPerSecond);
},
_ID2Color : function (ID) {
var intID = ID | 0;
var IDr = intID % 10;
var IDg = ((intID-IDr) / 10) % 10;
var IDb = ((((intID-IDr) / 10) - IDg) / 10) % 10;
var colorID = [IDr * 0.1, IDg * 0.1, IDb * 0.1, 1.0];
return colorID;
},
_Color2ID : function (color) {
var IDr = Math.round(((color[0])/255.0) / 0.1) | 0;
var IDg = (Math.round(((color[1])/255.0) / 0.1) * 10) | 0;
var IDb = (Math.round(((color[2])/255.0) / 0.1) * 100) | 0;
var ID = (IDr + IDg + IDb) | 0;
return ID;
},
_onPlyLoaded : function (req, thatmesh, gl) {
var plyData = req.buffer;
var modelDescriptor = importPly(plyData);
var TMR = thatmesh.renderable = new SglModel(gl, modelDescriptor);
TMR.renderMode = modelDescriptor.extra.renderMode;
TMR.boundingBox = modelDescriptor.extra.boundingBox;
// center and radius
TMR.datasetCenter = [0.0, 0.0, 0.0];
TMR.datasetRadius = 1.0;
TMR.datasetCenter[0] = (TMR.boundingBox.max[0] + TMR.boundingBox.min[0]) / 2.0;
TMR.datasetCenter[1] = (TMR.boundingBox.max[1] + TMR.boundingBox.min[1]) / 2.0;
TMR.datasetCenter[2] = (TMR.boundingBox.max[2] + TMR.boundingBox.min[2]) / 2.0;
TMR.datasetRadius = Math.sqrt( Math.pow((TMR.boundingBox.max[0] - TMR.boundingBox.min[0]),2) +
Math.pow((TMR.boundingBox.max[1] - TMR.boundingBox.min[1]),2) +
Math.pow((TMR.boundingBox.max[2] - TMR.boundingBox.min[2]),2) ) / 2.0;
// texture
if(modelDescriptor.extra.textureUrl) {
var that = this;
var texUrl = "";
var tmpUrl = req._url.split("/");
for (var j=0; j= 2) {// 0=inactive 1=picking pointA 2=picking pointB 3=measurement ready
// GLstate setup
gl.depthFunc(gl.LESS);
xform.model.push();
var lineUniforms = {
"uWorldViewProjectionMatrix" : xform.modelViewProjectionMatrix,
"uLineColor" : [config.measurementColor[0], config.measurementColor[1], config.measurementColor[2], 1.0],
"uPointA" : this._pointA,
"uPointB" : (this._measurementStage==2)?this._pointA:this._pointB,
};
//drawing points and line
renderer.begin();
renderer.setTechnique(lineTechnique);
renderer.setDefaultGlobals();
renderer.setGlobals(lineUniforms);
renderer.setPrimitiveMode("LINE");
renderer.setModel(this.simpleLineModel);
renderer.renderModel();
renderer.setPrimitiveMode("POINT");
renderer.setModel(this.simpleLineModel);
renderer.renderModel();
renderer.end();
lineUniforms["uLineColor"] = [config.measurementColor[0] * 0.4, config.measurementColor[1] * 0.5, config.measurementColor[2] * 0.6, 0.5];
gl.depthFunc(gl.GREATER);
gl.depthMask(false);
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
//drawing points and line
renderer.begin();
renderer.setTechnique(lineTechnique);
renderer.setDefaultGlobals();
renderer.setGlobals(lineUniforms);
renderer.setPrimitiveMode("LINE");
renderer.setModel(this.simpleLineModel);
renderer.renderModel();
renderer.setPrimitiveMode("POINT");
renderer.setModel(this.simpleLineModel);
renderer.renderModel();
renderer.end();
// GLstate cleanup
gl.disable(gl.BLEND);
gl.depthMask(true);
gl.depthFunc(gl.LESS);
xform.model.pop();
}
// draw entities
for (var ent in entities) {
var entity = entities[ent];
if (!entity.visible) continue;
if (!entity.renderable) continue;
xform.model.push();
xform.model.multiply(space.transform.matrix);
xform.model.multiply(entity.transform.matrix);
var entityUniforms = {
"uWorldViewProjectionMatrix" : xform.modelViewProjectionMatrix,
"uPointSize" : entity.pointSize,
"uColorID" : entity.color,
"uZOff" : entity.zOff,
};
if(entity.useTransparency)
{
gl.depthMask(false);
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
}
else
entityUniforms["uColorID"][3] = 1.0; // if no transparency, use full alpha, otherwise the entity cancels the background
//drawing entity
renderer.begin();
renderer.setTechnique(entitiesTechnique);
if (entity.type == "points")
renderer.setPrimitiveMode("POINT");
else if (entity.type == "lines" || entity.type == "lineStrip" || entity.type == "lineLoop")
renderer.setPrimitiveMode("LINE");
else if (entity.type == "triangles" || entity.type == "triangleStrip" || entity.type == "triangleFan")
renderer.setPrimitiveMode("FILL");
renderer.setDefaultGlobals();
renderer.setGlobals(entityUniforms);
renderer.setModel(entity.renderable);
renderer.renderModel();
renderer.end();
if(entity.useSeethrough) // draw seethrough
{
gl.depthFunc(gl.GREATER);
gl.depthMask(false);
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
entityUniforms["uColorID"] = [entity.color[0] * 0.4, entity.color[1] * 0.4, entity.color[2] * 0.4, entity.color[3] * 0.4]; // seethrough color
renderer.begin();
renderer.setTechnique(entitiesTechnique);
if (entity.type == "points")
renderer.setPrimitiveMode("POINT");
else if (entity.type == "lines" || entity.type == "lineStrip" || entity.type == "lineLoop")
renderer.setPrimitiveMode("LINE");
else if (entity.type == "triangles" || entity.type == "triangleStrip" || entity.type == "triangleFan")
renderer.setPrimitiveMode("FILL");
renderer.setDefaultGlobals();
renderer.setGlobals(entityUniforms);
renderer.setModel(entity.renderable);
renderer.renderModel();
renderer.end();
// GLstate cleanup
gl.disable(gl.BLEND);
gl.depthMask(true);
gl.depthFunc(gl.LESS);
}
if(entity.useTransparency)
{
gl.depthMask(true);
gl.disable(gl.BLEND);
}
xform.model.pop();
}
// draw transparent spot geometries
for (var spt in spots) {
var spot = spots[spt];
var mesh = meshes[spot.mesh];
if (!mesh) continue;
var renderable = mesh.renderable;
if (!renderable) continue;
if (!spot.visible) continue;
// GLstate setup
gl.depthMask(false);
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
xform.model.push();
xform.model.multiply(space.transform.matrix);
xform.model.multiply(spot.transform.matrix);
xform.model.multiply(mesh.transform.matrix);
var uniforms = {
"uWorldViewProjectionMatrix" : xform.modelViewProjectionMatrix,
"uViewSpaceNormalMatrix" : xform.viewSpaceNormalMatrix,
"uViewSpaceLightDirection" : this._lightDirection,
"uPointSize" : config.pointSize,
"uColorID" : [spot.color[0], spot.color[1], spot.color[2], (spt == this._pickedSpot)?spot.alphaHigh:spot.alpha]
}
if(mesh.mType === "nexus") {
if (!renderable.isReady) continue;
var nexus = renderable;
nexus.updateView([0, 0, width, height], xform.projectionMatrix, xform.modelViewMatrix);
var program = CCProgram;
program.setUniforms(uniforms);
program.bind();
nexus.setPrimitiveMode(spot.rendermode);
nexus.render();
program.unbind();
}
else if(mesh.mType === "ply") {
renderer.begin();
renderer.setTechnique(CCTechnique);
renderer.setDefaultGlobals();
renderer.setPrimitiveMode(spot.rendermode);
renderer.setGlobals(uniforms);
renderer.setModel(renderable);
if(spot.useStencil)
{
gl.clear(gl.STENCIL_BUFFER_BIT); //reset stencil
//first pass
gl.colorMask(false, false, false, false);
gl.enable(gl.STENCIL_TEST);
gl.stencilFunc(gl.ALWAYS, 0, 255);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.INVERT);
renderer.renderModel();
//second pass
gl.colorMask(true, true, true, true);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.INVERT); // Don't change the stencil buffer...
gl.stencilFunc(gl.EQUAL, 1, 0x01); // The stencil buffer contains the shadow values...
renderer.renderModel();
gl.disable(gl.STENCIL_TEST);
}
else
{
renderer.renderModel();
}
renderer.end();
}
// GLstate cleanup
gl.disable(gl.BLEND);
gl.depthMask(true);
xform.model.pop();
}
// draw clipping plane (if any)
if(config.showClippingPlanes)
{
// GLstate setup
gl.depthMask(false);
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
if(SglVec3.length([this._clipPlane[0], this._clipPlane[1], this._clipPlane[2]]) > 0.0) {
var planepoint = [0.0, 0.0, 0.0];
var k = SglVec3.dot(this._sceneBboxCenter, [this._clipPlane[0], this._clipPlane[1], this._clipPlane[2]]) + this._clipPlane[3];
planepoint[0] = this._sceneBboxCenter[0] - (this._clipPlane[0] * k);
planepoint[1] = this._sceneBboxCenter[1] - (this._clipPlane[1] * k);
planepoint[2] = this._sceneBboxCenter[2] - (this._clipPlane[2] * k);
var rotm = SglMat4.identity();
rotm = SglMat4.mul(rotm, SglMat4.rotationAngleAxis(sglDegToRad(this._clipPlaneAH), [0.0, -1.0, 0.0]));
rotm = SglMat4.mul(rotm, SglMat4.rotationAngleAxis(sglDegToRad(this._clipPlaneAV), [0.0, 0.0, 1.0]));
var psize = this._sceneBboxDiag;
xform.model.push();
xform.model.translate(planepoint);
xform.model.multiply(rotm);
xform.model.scale([psize, psize, psize]);
var QuadUniforms = {
"uWorldViewProjectionMatrix" : xform.modelViewProjectionMatrix,
"uViewSpaceNormalMatrix" : xform.viewSpaceNormalMatrix,
"uViewSpaceLightDirection" : this._lightDirection,
"uColorID" : [1.0, 0.0, 1.0, 0.25]
};
renderer.begin();
renderer.setTechnique(CCTechnique);
renderer.setDefaultGlobals();
renderer.setPrimitiveMode("FILL");
renderer.setGlobals(QuadUniforms);
renderer.setModel(this.simpleQuadXModel);
renderer.renderModel();
renderer.end();
xform.model.pop();
}
if(this._clipAxis[0] != 0.0) {
xform.model.push();
xform.model.translate([this._clipPoint[0], this._sceneBboxCenter[1], this._sceneBboxCenter[2]]);
xform.model.scale([(this._sceneBboxMax[0] - this._sceneBboxMin[0]),
(this._sceneBboxMax[1] - this._sceneBboxMin[1]),
(this._sceneBboxMax[2] - this._sceneBboxMin[2])]);
var QuadUniforms = {
"uWorldViewProjectionMatrix" : xform.modelViewProjectionMatrix,
"uViewSpaceNormalMatrix" : xform.viewSpaceNormalMatrix,
"uViewSpaceLightDirection" : this._lightDirection,
"uColorID" : [1.0, 0.0, 0.0, 0.25]
};
renderer.begin();
renderer.setTechnique(CCTechnique);
renderer.setDefaultGlobals();
renderer.setPrimitiveMode("FILL");
renderer.setGlobals(QuadUniforms);
renderer.setModel(this.simpleQuadXModel);
renderer.renderModel();
renderer.end();
xform.model.pop();
}
if(this._clipAxis[1] != 0.0) {
xform.model.push();
xform.model.translate([this._sceneBboxCenter[0], this._clipPoint[1], this._sceneBboxCenter[2]]);
xform.model.scale([(this._sceneBboxMax[0] - this._sceneBboxMin[0]),
(this._sceneBboxMax[1] - this._sceneBboxMin[1]),
(this._sceneBboxMax[2] - this._sceneBboxMin[2])]);
var QuadUniforms = {
"uWorldViewProjectionMatrix" : xform.modelViewProjectionMatrix,
"uViewSpaceNormalMatrix" : xform.viewSpaceNormalMatrix,
"uViewSpaceLightDirection" : this._lightDirection,
"uColorID" : [0.0, 1.0, 0.0, 0.25]
};
renderer.begin();
renderer.setTechnique(CCTechnique);
renderer.setDefaultGlobals();
renderer.setPrimitiveMode("FILL");
renderer.setGlobals(QuadUniforms);
renderer.setModel(this.simpleQuadYModel);
renderer.renderModel();
renderer.end();
xform.model.pop();
}
if(this._clipAxis[2] != 0.0) {
xform.model.push();
xform.model.translate([this._sceneBboxCenter[0], this._sceneBboxCenter[1], this._clipPoint[2]]);
xform.model.scale([(this._sceneBboxMax[0] - this._sceneBboxMin[0]),
(this._sceneBboxMax[1] - this._sceneBboxMin[1]),
(this._sceneBboxMax[2] - this._sceneBboxMin[2])]);
var QuadUniforms = {
"uWorldViewProjectionMatrix" : xform.modelViewProjectionMatrix,
"uViewSpaceNormalMatrix" : xform.viewSpaceNormalMatrix,
"uViewSpaceLightDirection" : this._lightDirection,
"uColorID" : [0.0, 0.0, 1.0, 0.25]
};
renderer.begin();
renderer.setTechnique(CCTechnique);
renderer.setDefaultGlobals();
renderer.setPrimitiveMode("FILL");
renderer.setGlobals(QuadUniforms);
renderer.setModel(this.simpleQuadZModel);
renderer.renderModel();
renderer.end();
xform.model.pop();
}
// GLstate cleanup
gl.disable(gl.BLEND);
gl.depthMask(true);
}
Nexus.endFrame(this.ui.gl);
// saving image, if necessary
if(this.isCapturingScreenshot){
this.isCapturingScreenshot = false;
this.screenshotData = this.ui._canvas.toDataURL('image/png',1).replace("image/png", "image/octet-stream");
if(this._scene.config.autoSaveScreenshot)
{
var currentdate = new Date();
var fName = this._scene.config.screenshotBaseName;
if(this._scene.config.screenshotTime) fName += "_" + String(currentdate.getHours()).padStart(2, '0') + String(currentdate.getMinutes()).padStart(2, '0') + String(currentdate.getSeconds()).padStart(2, '0');
fName += ".png";
this._saveImage(fName);
}
}
},
_saveImage : function(fName){
if(this.ui._canvas.msToBlob) // IE or EDGEhtml
{
console.error("IE and EDGEhtml cannot save images");
var blob = this.ui._canvas.msToBlob();
window.navigator.msSaveBlob(blob, fName);
}
else // every other browser
{
var a = document.createElement('a');
a.href = this.screenshotData;
a.download = fName;
a.target="_blank";
a.click();
}
},
_drawScenePickingXYZ : function () {
var gl = this.ui.gl;
var width = this.ui.width;
var height = this.ui.height;
var xform = this.xform;
var renderer = this.renderer;
var CurrProgram = this.utilsProgram;
var CurrTechnique = this.utilsTechnique;
var meshes = this._scene.meshes;
var instances = this._scene.modelInstances;
var space = this._scene.space;
var pixel = new Uint8Array(4);
// picking FB
this._createPickFramebuffer(width, height);
// basic setup, matrices for projection & view
this._setupDraw();
// clear buffer
this.pickFramebuffer.bind();
gl.clearColor(0.0, 0.0, 0.0, 0.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
gl.enable(gl.DEPTH_TEST);
this.pickFramebuffer.unbind();
for (var inst in instances) {
var instance = instances[inst];
var mesh = meshes[instance.mesh];
if (!mesh) continue;
var renderable = mesh.renderable;
if (!renderable) continue;
if (!instance.visible) continue;
if (!instance.measurable) continue;
// GLstate setup
xform.model.push();
xform.model.multiply(space.transform.matrix);
xform.model.multiply(instance.transform.matrix);
xform.model.multiply(mesh.transform.matrix);
var modelMatrix = SglMat4.identity();
modelMatrix = SglMat4.mul(modelMatrix, space.transform.matrix);
modelMatrix = SglMat4.mul(modelMatrix, instance.transform.matrix);
modelMatrix = SglMat4.mul(modelMatrix, mesh.transform.matrix);
var thisClipAxis = instance.clippable?this._clipAxis:[0.0, 0.0, 0.0];
var thisClipPlane = instance.clippable?this._clipPlane:[0.0, 0.0, 0.0, 0.0];
var uniforms = {
"uWorldViewProjectionMatrix" : xform.modelViewProjectionMatrix,
"uModelMatrix" : modelMatrix,
"uBackFaceColor" : instance.backfaceColor,
"uClipPoint" : this._clipPoint,
"uClipAxis" : thisClipAxis,
"uClipPlane" : thisClipPlane,
"uPointSize" : this._scene.config.pointSize,
"uMode" : 1.0
};
if(mesh.mType === "nexus") {
if (!renderable.isReady) continue;
var nexus = renderable;
nexus.updateView([0, 0, width, height], xform.projectionMatrix, xform.modelViewMatrix);
this.pickFramebuffer.bind();
var program = CurrProgram;
program.setUniforms(uniforms);
program.bind();
nexus.setPrimitiveMode(instance.rendermode);
nexus.render();
program.unbind();
this.pickFramebuffer.unbind();
}
else if(mesh.mType === "ply") {
renderer.begin();
renderer.setFramebuffer(this.pickFramebuffer);
renderer.setTechnique(CurrTechnique);
renderer.setDefaultGlobals();
renderer.setPrimitiveMode(instance.rendermode);
renderer.setGlobals(uniforms);
renderer.setModel(renderable);
renderer.renderModel();
renderer.setFramebuffer(null);
renderer.end();
}
// GLstate cleanup
xform.model.pop();
}
this.pickFramebuffer.readPixels(pixel, {
x : this._pickpoint[0],
y : this._pickpoint[1],
width : 1,
height : 1,
format : gl.RGBA,
type : gl.UNSIGNED_BYTE
});
var rr = pixel[0] / 255.0;
var gg = pixel[1] / 255.0;
var bb = pixel[2] / 255.0;
var aa = pixel[3] / 255.0;
var depth = aa + ( bb / (255.0)) + ( gg / (255.0*255.0)) + ( rr / (255.0*255.0*255.0));
var ppointc;
if((rr==0.0) && (gg==0.0) && (bb==0.0))
return(null);
else
ppointc = xform.unproject([this._pickpoint[0]/width,this._pickpoint[1]/height,depth]);
return([ppointc[0], ppointc[1], ppointc[2]]);
},
_drawScenePickingInstances : function () {
var gl = this.ui.gl;
var width = this.ui.width;
var height = this.ui.height;
var xform = this.xform;
var renderer = this.renderer;
var CurrProgram = this.utilsProgram;
var CurrTechnique = this.utilsTechnique;
var meshes = this._scene.meshes;
var instances = this._scene.modelInstances;
var space = this._scene.space;
var pixel = new Uint8Array(4);
// picking FB
this._createPickFramebuffer(width, height);
// basic setup, matrices for projection & view
this._setupDraw();
// clear buffer
this.pickFramebuffer.bind();
gl.clearColor(0.0, 0.0, 0.0, 0.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
gl.enable(gl.DEPTH_TEST);
this.pickFramebuffer.unbind();
for (var inst in instances) {
var instance = instances[inst];
var mesh = meshes[instance.mesh];
if (!mesh) continue;
var renderable = mesh.renderable;
if (!renderable) continue;
if (!instance.visible) continue;
// GLstate setup
xform.model.push();
xform.model.multiply(space.transform.matrix);
xform.model.multiply(instance.transform.matrix);
xform.model.multiply(mesh.transform.matrix);
var modelMatrix = SglMat4.identity();
modelMatrix = SglMat4.mul(modelMatrix, space.transform.matrix);
modelMatrix = SglMat4.mul(modelMatrix, instance.transform.matrix);
modelMatrix = SglMat4.mul(modelMatrix, mesh.transform.matrix);
var thisClipAxis = instance.clippable?this._clipAxis:[0.0, 0.0, 0.0];
var thisClipPlane = instance.clippable?this._clipPlane:[0.0, 0.0, 0.0, 0.0];
var colorID = this._ID2Color(instance.ID);
var uniforms = {
"uWorldViewProjectionMatrix" : xform.modelViewProjectionMatrix,
"uModelMatrix" : modelMatrix,
"uClipPoint" : this._clipPoint,
"uClipAxis" : thisClipAxis,
"uClipPlane" : thisClipPlane,
"uPointSize" : this._scene.config.pointSize,
"uColorID" : colorID,
"uMode" : 2.0
};
if(mesh.mType === "nexus") {
if (!renderable.isReady) continue;
var nexus = renderable;
nexus.updateView([0, 0, width, height], xform.projectionMatrix, xform.modelViewMatrix);
this.pickFramebuffer.bind();
var program = CurrProgram;
program.setUniforms(uniforms);
program.bind();
nexus.setPrimitiveMode(instance.rendermode);
nexus.render();
program.unbind();
this.pickFramebuffer.unbind();
}
else if(mesh.mType === "ply") {
renderer.begin();
renderer.setFramebuffer(this.pickFramebuffer);
renderer.setTechnique(CurrTechnique);
renderer.setDefaultGlobals();
renderer.setPrimitiveMode(instance.rendermode);
renderer.setGlobals(uniforms);
renderer.setModel(renderable);
renderer.renderModel();
renderer.setFramebuffer(null);
renderer.end();
}
// GLstate cleanup
xform.model.pop();
}
this.pickFramebuffer.readPixels(pixel, {
x : this._pickpoint[0],
y : this._pickpoint[1],
width : 1,
height : 1,
format : gl.RGBA,
type : gl.UNSIGNED_BYTE
});
return pixel;
},
_drawScenePickingSpots : function () {
var gl = this.ui.gl;
var width = this.ui.width;
var height = this.ui.height;
var xform = this.xform;
var renderer = this.renderer;
var CurrProgram = this.utilsProgram;
var CurrTechnique = this.utilsTechnique;
var meshes = this._scene.meshes;
var spots = this._scene.spots;
var instances = this._scene.modelInstances;
var space = this._scene.space;
var pixel = new Uint8Array(4);
// picking FB
this._createPickFramebuffer(width, height);
// basic setup, matrices for projection & view
this._setupDraw();
// clear buffer
this.pickFramebuffer.bind();
gl.clearColor(0.0, 0.0, 0.0, 0.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
gl.enable(gl.DEPTH_TEST);
this.pickFramebuffer.unbind();
// first pass, draw invisible instances, for occlusion
for (var inst in instances) {
var instance = instances[inst];
var mesh = meshes[instance.mesh];
if (!mesh) continue;
var renderable = mesh.renderable;
if (!renderable) continue;
if (!instance.visible) continue;
// GLstate setup
xform.model.push();
xform.model.multiply(space.transform.matrix);
xform.model.multiply(instance.transform.matrix);
xform.model.multiply(mesh.transform.matrix);
var uniforms = {
"uWorldViewProjectionMatrix" : xform.modelViewProjectionMatrix,
"uPointSize" : this._scene.config.pointSize,
"uColorID" : [0.0, 0.0, 0.0, 0.0],
"uMode" : 2.0
};
if(mesh.mType === "nexus") {
if (!renderable.isReady) continue;
var nexus = renderable;
nexus.updateView([0, 0, width, height], xform.projectionMatrix, xform.modelViewMatrix);
this.pickFramebuffer.bind();
var program = CurrProgram;
program.setUniforms(uniforms);
program.bind();
nexus.setPrimitiveMode(instance.rendermode);
nexus.render();
program.unbind();
this.pickFramebuffer.unbind();
}
else if(mesh.mType === "ply") {
renderer.begin();
renderer.setFramebuffer(this.pickFramebuffer);
renderer.setTechnique(CurrTechnique);
renderer.setDefaultGlobals();
renderer.setPrimitiveMode(instance.rendermode);
renderer.setGlobals(uniforms);
renderer.setModel(renderable);
renderer.renderModel();
renderer.setFramebuffer(null);
renderer.end();
}
// GLstate cleanup
xform.model.pop();
}
// second pass, draw color coded spots, for picking
for (var spt in spots) {
var spot = spots[spt];
var mesh = meshes[spot.mesh];
if (!mesh) continue;
var renderable = mesh.renderable;
if (!renderable) continue;
if (!spot.visible) continue;
// GLstate setup
xform.model.push();
xform.model.multiply(space.transform.matrix);
xform.model.multiply(spot.transform.matrix);
xform.model.multiply(mesh.transform.matrix);
var colorID = this._ID2Color(spot.ID);
var uniforms = {
"uWorldViewProjectionMatrix" : xform.modelViewProjectionMatrix,
"uPointSize" : this._scene.config.pointSize,
"uColorID" : colorID,
"uMode" : 2.0
};
if(mesh.mType === "nexus") {
if (!renderable.isReady) continue;
var nexus = renderable;
nexus.updateView([0, 0, width, height], xform.projectionMatrix, xform.modelViewMatrix);
this.pickFramebuffer.bind();
var program = CurrProgram;
program.setUniforms(uniforms);
program.bind();
nexus.setPrimitiveMode(spot.rendermode);
nexus.render();
program.unbind();
this.pickFramebuffer.unbind();
}
else if(mesh.mType === "ply") {
renderer.begin();
renderer.setFramebuffer(this.pickFramebuffer);
renderer.setTechnique(CurrTechnique);
renderer.setDefaultGlobals();
renderer.setPrimitiveMode(spot.rendermode);
renderer.setGlobals(uniforms);
renderer.setModel(renderable);
renderer.renderModel();
renderer.setFramebuffer(null);
renderer.end();
}
// GLstate cleanup
xform.model.pop();
gl.depthMask(true);
}
this.pickFramebuffer.readPixels(pixel, {
x : this._pickpoint[0],
y : this._pickpoint[1],
width : 1,
height : 1,
format : gl.RGBA,
type : gl.UNSIGNED_BYTE
});
return pixel;
},
_drawNull : function () {
var gl = this.ui.gl;
gl.clearColor(0.0, 0.0, 0.0, 0.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
},
// creates mesh models
_createMeshModels : function () {
var that = this;
var gl = this.ui.gl;
for(var keys = Object.keys(this._scene.meshes), i = keys.length-1; i >= 0; i--) {
var m = keys[i];
var mesh = this._scene.meshes[m];
if (!mesh.url) continue;
if (this._objectsToProcess == 0) this._testReady();
else {
this._objectsToProcess--;
if(mesh.mType == null)
{
var ext = mesh.url.split('.').pop().split(/\#|\?/)[0].toLowerCase();
if((ext === "nxs") || (ext === "nxz"))
mesh.mType = "nexus";
else if(ext === "ply")
mesh.mType = "ply";
}
if(mesh.mType === "nexus") {
var nexus_instance = new Nexus.Renderer(gl);
nexus_instance.onLoad = function () { that._onMeshReady(); };
nexus_instance.onUpdate = this.ui.postDrawEvent;
mesh.renderable = nexus_instance;
nexus_instance.open(mesh.url);
}
else if(mesh.mType === "ply") {
mesh.renderable = null;
sglRequestBinary(mesh.url, {
onSuccess : (function(m){ return function (req) { that._onPlyLoaded(req, m, gl); }; })(mesh)
});
}
}
}
},
// creates simple 2-point line model
_createLineModel : function () {
var gl = this.ui.gl;
this.simpleLineModel = new SglModel(gl, {
vertices : {
position : [ 0,0,0,
1,1,1 ],
normal : [ 0,0,0,
0,0,0 ],
color : {value : [ 1.0, 0.0, 0.0 ]}
},
primitives : ["lines","points"]
});
},
// creates simple quad model
_createQuadModels : function () {
var gl = this.ui.gl;
this.simpleQuadXModel = new SglModel(gl, {
vertices : {
position : [ 0.0, 0.5, 0.5,
0.0,-0.5, 0.5,
0.0,-0.5,-0.5,
0.0, 0.5,-0.5,
0.0,-0.5,-0.5,
0.0, 0.5, 0.5],
normal : [ 1.0,0.0,0.0,
1.0,0.0,0.0,
1.0,0.0,0.0,
1.0,0.0,0.0,
1.0,0.0,0.0,
1.0,0.0,0.0 ],
color : {value : [ 1.0, 0.0, 0.0 ]}
},
primitives : ["triangles"]
});
this.simpleQuadYModel = new SglModel(gl, {
vertices : {
position : [ 0.5, 0.0, 0.5,
-0.5, 0.0, 0.5,
-0.5, 0.0,-0.5,
0.5, 0.0,-0.5,
-0.5, 0.0,-0.5,
0.5, 0.0, 0.5],
normal : [ 0.0,1.0,0.0,
0.0,1.0,0.0,
0.0,1.0,0.0,
0.0,1.0,0.0,
0.0,1.0,0.0,
0.0,1.0,0.0 ],
color : {value : [ 0.0, 1.0, 0.0 ]}
},
primitives : ["triangles"]
});
this.simpleQuadZModel = new SglModel(gl, {
vertices : {
position : [ 0.5, 0.5, 0.0,
-0.5, 0.5, 0.0,
-0.5,-0.5, 0.0,
0.5,-0.5, 0.0,
-0.5,-0.5, 0.0,
0.5, 0.5, 0.0],
normal : [ 0.0,0.0,1.0,
0.0,0.0,1.0,
0.0,0.0,1.0,
0.0,0.0,1.0,
0.0,0.0,1.0,
0.0,0.0,1.0 ],
color : {value : [ 0.0, 0.0, 1.0 ]}
},
primitives : ["triangles"]
});
},
//----------------------------------------------------------------------------------------
// EVENTS HANDLERS
//----------------------------------------------------------------------------------------
onInitialize : function () {
var gl = this.ui.gl;
gl.getExtension('EXT_frag_depth');
gl.clearColor(0.5, 0.5, 0.5, 1.0);
gl.clearStencil(0);
gl.depthFunc(gl.LESS);
// vertex attrib defaults
gl.vertexAttrib3f(1.0, 0.0, 0.0, 0.0); //1 aNormal
gl.vertexAttrib4f(2.0, 0.8, 0.8, 0.8, 1.0); //2 aColor
gl.vertexAttrib2f(3.0, 0.0, 0.0); //3 aTextureCoord
gl.vertexAttrib1f(4.0, 1.0); //4 aPointSize
// scene rendering support data
this.renderer = new SglModelRenderer(gl);
this.xform = new SglTransformationStack();
this.viewMatrix = SglMat4.identity();
// nexus parameters
this.setNexusTargetError(1.0);
this.setNexusMinFps(15.0);
this.setNexusMaxCacheSize(512*(1<<20)); //512MB
// debug mode
this._isDebugging = HOP_DEBUGMODE;
// shaders
this.installDefaultShaders();
// screenshot support
this.isCapturingScreenshot = false;
this.screenshotData = null;
// handlers
this._onPickedInstance = 0;
this._onPickedSpot = 0;
this._onEnterInstance = 0;
this._onEnterSpot = 0;
this._onLeaveInstance = 0;
this._onLeaveSpot = 0;
this._onEndPickingPoint = 0;
this._onEndMeasurement = 0;
// animation
this.ui.animateRate = 0;
// current cursor XY position normalized [-1 1] on canvas size, and delta
this.x = 0.0;
this.y = 0.0;
// scene data
this._scene = null;
this._sceneParsed = false;
this._sceneReady = false;
this._objectsToProcess = 0;
this._objectsToLoad = 0;
this._instancesProgressiveID = 1;
this._spotsProgressiveID = 1;
this._lightDirection = HOP_DEFAULTLIGHT;
this.sceneCenter = [0.0, 0.0, 0.0];
this.sceneRadiusInv = 1.0;
this._targetInstanceName = null;
this._targetHotSpotName = null;
this._animating = false;
this._movingLight = false;
this._resizable = true;
this._clickable = false;
this._onHover = false;
this._lastCursor = "default";
this._pickedInstance = null;
this._pickedSpot = null;
this._lastPickedInstance = null;
this._lastPickedSpot = null;
this._lastInstanceID = 0;
this._lastSpotID = 0;
this._pickpoint = [1, 1];
this._keycombo = false;
// global measurement data
this._isMeasuring = false;
// point2point measurement data
this._isMeasuringDistance = false;
this._measurementStage = 0; // 0=inactive 1=picking pointA 2=picking pointB 3=measurement ready
this._pointA = [0.0, 0.0, 0.0];
this._pointB = [0.0, 0.0, 0.0];
this.measurement = 0;
// point picking measurement data
this._isMeasuringPickpoint = false;
this._pickValid = false;
this._pickedPoint = [0.0, 0.0, 0.0];
// plane section
this._clipPoint = [0.0, 0.0, 0.0];
this._clipAxis = [0.0, 0.0, 0.0];
this._clipPlane = [0.0, 0.0, 0.0, 0.0];
this._sceneBboxMin = [0.0, 0.0, 0.0]
this._sceneBboxMax = [0.0, 0.0, 0.0];
this._sceneBboxCenter = [0.0, 0.0, 0.0];
this._sceneBboxDiag = 0.0;
},
installDefaultShaders : function () {
this.facesProgram = this._createStandardFacesProgram();
this.pointsProgram = this._createStandardPointsProgram();
this.utilsProgram = this._createUtilsProgram();
this.colorShadedProgram = this._createColorShadedProgram();
this.faceTechnique = this._createStandardFacesTechnique();
this.pointTechnique = this._createStandardPointsTechnique();
this.utilsTechnique = this._createUtilsTechnique();
this.colorShadedTechnique = this._createColorShadedTechnique();
this.simpleLineTechnique = this._createSimpleLinetechnique();
this.multiLinesPointsTechnique = this._createMultiLinesPointstechnique();
},
onDrag : function (button, x, y, e) {
var ui = this.ui;
this.x = (x / (ui.width - 1)) * 2.0 - 1.0;
this.y = (y / (ui.height - 1)) * 2.0 - 1.0;
if(this._clickable) this._clickable = false;
if(this._movingLight && ui.isMouseButtonDown(0)){
this.rotateLight(this.x/2.0, this.y/2.0);
return;
}
// if locked trackball, just return. we check AFTER the light-trackball test
if (this._scene.trackball.locked) return;
var action = SGL_TRACKBALL_NO_ACTION;
if ((ui.isMouseButtonDown(0) && ui.isKeyDown(17)) || ui.isMouseButtonDown(1) || ui.isMouseButtonDown(2)) {
action = SGL_TRACKBALL_PAN;
}
else if (ui.isMouseButtonDown(0)) {
action = SGL_TRACKBALL_ROTATE;
}
var testMatrix = this.trackball._matrix.slice();
this.trackball.action = action;
this.trackball.track(this.viewMatrix, this.x*this._scene.trackball.dragSpeed, this.y*this._scene.trackball.dragSpeed, 0.0);
var diff;
for(var i=0; i this._scene.config.pointSizeMinMax[1]) this._scene.config.pointSize = this._scene.config.pointSizeMinMax[1];
if(testValue!=this._scene.config.pointSize) {
diff=true;
}
}
else {
// if locked trackball, just return.
if (this._scene.trackball.locked) return;
var action = SGL_TRACKBALL_SCALE;
var factor = wheelDelta > 0.0 ? (0.90) : (1.10);
var testMatrix = this.trackball._matrix.slice();
this.trackball.action = action;
this.trackball.track(this.viewMatrix, 0.0, 0.0, factor);
this.trackball.action = SGL_TRACKBALL_NO_ACTION;
for(var i=0; i 0) this._animating = true;
else this._animating = false;
return this._animating;
},
//-----------------------------------------------------------------------------
// dynamic center/radius mode
setCenterModeFirst : function () {
this._scene.space.centerMode = "first";
this.repaint();
},
setCenterModeScene : function () {
this._scene.space.centerMode = "scene";
this.repaint();
},
setCenterModeSpecific : function (instancename) {
if(this._scene.modelInstances[instancename])
{
this._scene.space.centerMode = "specific";
this._scene.space.whichInstanceCenter = instancename;
this.repaint();
}
else
return "ERROR - No such instance";
},
setCenterModeExplicit : function (newcenter) {
if((newcenter.constructor === Array)&&(newcenter.length = 3)&&(isFinite(String(newcenter[0])))&&(isFinite(String(newcenter[1])))&&(isFinite(String(newcenter[2]))))
{
this._scene.space.centerMode = "explicit";
this._scene.space.explicitCenter = newcenter;
this.repaint();
}
else
return "ERROR - Not a point";
},
setRadiusModeFirst : function () {
this._scene.space.radiusMode = "first";
this.repaint();
},
setRadiusModeScene : function () {
this._scene.space.radiusMode = "scene";
this.repaint();
},
setRadiusModeSpecific : function (instancename) {
if(this._scene.modelInstances[instancename])
{
this._scene.space.radiusMode = "specific";
this._scene.space.whichInstanceRadius = instancename;
this.repaint();
}
else
return "ERROR - No such instance";
},
setRadiusModeExplicit : function (newradius) {
if((isFinite(String(newradius)))&&(newradius>0.0))
{
this._scene.space.radiusMode = "explicit";
this._scene.space.explicitRadius = newradius;
this.repaint();
}
else
return "ERROR - Not a radius";
},
//-----------------------------------------------------------------------------
// instance solid color
setInstanceSolidColorByName : function (name, newState, redraw, newColor) {
var instances = this._scene.modelInstances;
if(name == HOP_ALL) {
for (var inst in instances) {
instances[inst].useSolidColor = newState;
if(newColor)
instances[inst].color = newColor;
}
}
else {
if(instances[name]) { // if an instance with that name exists
instances[name].useSolidColor = newState;
if(newColor)
instances[name].color = newColor;
}
}
if(redraw)
this.repaint();
},
setInstanceSolidColor : function (tag, newState, redraw, newColor) {
var instances = this._scene.modelInstances;
for (var inst in instances) {
if(tag == HOP_ALL) {
instances[inst].useSolidColor = newState;
if(newColor)
instances[inst].color = newColor;
}
else {
for (var tg in instances[inst].tags){
if(instances[inst].tags[tg] == tag){
instances[inst].useSolidColor = newState;
if(newColor)
instances[inst].color = newColor;
}
}
}
}
if(redraw)
this.repaint();
},
toggleInstanceSolidColorByName : function (name, redraw) {
var instances = this._scene.modelInstances;
if(name == HOP_ALL)
for (var inst in instances)
instances[inst].useSolidColor = !instances[inst].useSolidColor;
else
if(instances[name]) // if an instance with that name exists
instances[name].useSolidColor = !instances[name].useSolidColor;
if(redraw)
this.repaint();
},
toggleInstanceSolidColor : function (tag, redraw) {
var instances = this._scene.modelInstances;
for (var inst in instances) {
if(tag == HOP_ALL)
instances[inst].useSolidColor = !instances[inst].useSolidColor;
else
for (var tg in instances[inst].tags)
if(instances[inst].tags[tg] == tag)
instances[inst].useSolidColor = !instances[inst].useSolidColor;
}
if(redraw)
this.repaint();
},
isInstanceSolidColorEnabledByName : function (name) {
var solidcolor = false;
var instances = this._scene.modelInstances;
if(!name || name==HOP_ALL) {
for (var inst in instances) {
if(instances[inst].useSolidColor){
solidcolor = true;
return solidcolor;
}
}
}
else {
if(instances[name]) { // if an instance with that name exists
if(instances[name].useSolidColor){
solidcolor = true;
return solidcolor;
}
}
}
return solidcolor;
},
isInstanceSolidColorEnabled : function (tag) {
var solidcolor = false;
var instances = this._scene.modelInstances;
for (var inst in instances) {
if(!tag || tag==HOP_ALL){
if(instances[inst].useSolidColor){
solidcolor = true;
return solidcolor;
}
}
else{
for (var tg in instances[inst].tags){
if(instances[inst].tags[tg] == tag){
if(instances[inst].useSolidColor){
solidcolor = true;
return solidcolor;
}
}
}
}
}
return solidcolor;
},
//-----------------------------------------------------------------------------
// instance transparency
setInstanceTransparencyByName : function (name, newState, redraw, newAlpha) {
var instances = this._scene.modelInstances;
if(name == HOP_ALL) {
for (var inst in instances)
instances[inst].useTransparency = newState;
if(newAlpha)
instances[inst].alpha = newAlpha;
}
else {
if(instances[name]) { // if an instance with that name exists
instances[name].useTransparency = newState;
if(newAlpha)
instances[name].alpha = newAlpha;
}
}
if(redraw)
this.repaint();
},
setInstanceTransparency : function (tag, newState, redraw, newAlpha) {
var instances = this._scene.modelInstances;
for (var inst in instances) {
if(tag == HOP_ALL) {
instances[inst].useTransparency = newState;
if(newAlpha)
instances[inst].alpha = newAlpha;
}
else {
for (var tg in instances[inst].tags){
if(instances[inst].tags[tg] == tag){
instances[inst].useTransparency = newState;
if(newAlpha)
instances[inst].alpha = newAlpha;
}
}
}
}
if(redraw)
this.repaint();
},
toggleInstanceTransparencyByName : function (name, redraw) {
var instances = this._scene.modelInstances;
if(name == HOP_ALL) {
for (var inst in instances)
instances[inst].useTransparency = !instances[inst].useTransparency;
}
else {
if(instances[name]) // if an instance with that name exists
instances[name].useTransparency = !instances[name].useTransparency;
}
if(redraw)
this.repaint();
},
toggleInstanceTransparency : function (tag, redraw) {
var instances = this._scene.modelInstances;
for (var inst in instances) {
if(tag == HOP_ALL)
{
instances[inst].useTransparency = !instances[inst].useTransparency;
}
else
{
for (var tg in instances[inst].tags){
if(instances[inst].tags[tg] == tag)
instances[inst].useTransparency = !instances[inst].useTransparency;
}
}
}
if(redraw)
this.repaint();
},
isInstanceTransparencyEnabledByName : function (name) {
var transparency = false;
var instances = this._scene.modelInstances;
if(!name || name==HOP_ALL) {
for (var inst in instances) {
if(instances[inst].useTransparency){
transparency = true;
return transparency;
}
}
}
else {
if(instances[name]) { // if an instance with that name exists
if(instances[name].useTransparency){
transparency = true;
return transparency;
}
}
}
return transparency;
},
isInstanceTransparencyEnabled : function (tag) {
var transparency = false;
var instances = this._scene.modelInstances;
for (var inst in instances) {
if(!tag || tag==HOP_ALL){
if(instances[inst].useTransparency){
transparency = true;
return transparency;
}
}
else{
for (var tg in instances[inst].tags){
if(instances[inst].tags[tg] == tag){
if(instances[inst].useTransparency){
transparency = true;
return transparency;
}
}
}
}
}
return transparency;
},
//-----------------------------------------------------------------------------
// instance shading
//----specular
setInstanceSpecularityByName : function (name, color, hardness, redraw) {
var instances = this._scene.modelInstances;
if(name == HOP_ALL) {
for (var inst in instances)
instances[inst].specularColor = [color[0], color[1], color[2], hardness];
}
else {
if(instances[name]) // if an instance with that name exists
instances[name].specularColor = [color[0], color[1], color[2], hardness];
}
if(redraw)
this.repaint();
},
setInstanceSpecularity : function (tag, color, hardness, redraw) {
var instances = this._scene.modelInstances;
for (var inst in instances) {
if(tag == HOP_ALL) {
instances[inst].specularColor = [color[0], color[1], color[2], hardness];
}
else {
for (var tg in instances[inst].tags){
if(instances[inst].tags[tg] == tag)
instances[inst].specularColor = [color[0], color[1], color[2], hardness];
}
}
}
if(redraw)
this.repaint();
},
//----backface
setInstanceBackfaceByName : function (name, color, mode, redraw) {
var instances = this._scene.modelInstances;
var modecode = 0.0;
if (mode == "tint") modecode = 0.0;
else if (mode == "fill") modecode = 1.0;
else if (mode == "cull") modecode = 2.0;
if(name == HOP_ALL) {
for (var inst in instances)
instances[inst].backfaceColor = [color[0], color[1], color[2], modecode];
}
else {
if(instances[name]) // if an instance with that name exists
instances[name].backfaceColor = [color[0], color[1], color[2], modecode];
}
if(redraw)
this.repaint();
},
setInstanceBackface : function (tag, color, mode, redraw) {
var instances = this._scene.modelInstances;
var modecode = 0.0;
if (mode == "tint") modecode = 0.0;
else if (mode == "fill") modecode = 1.0;
else if (mode == "cull") modecode = 2.0;
for (var inst in instances) {
if(tag == HOP_ALL) {
instances[inst].backfaceColor = [color[0], color[1], color[2], modecode];
}
else {
for (var tg in instances[inst].tags){
if(instances[inst].tags[tg] == tag)
instances[inst].backfaceColor = [color[0], color[1], color[2], modecode];
}
}
}
if(redraw)
this.repaint();
},
//-----------------------------------------------------------------------------
// instance visibility
setInstanceVisibilityByName : function (name, newState, redraw) {
var instances = this._scene.modelInstances;
if(name == HOP_ALL) {
for (var inst in instances)
instances[inst].visible = newState;
}
else {
if(instances[name]) // if an instance with that name exists
instances[name].visible = newState;
}
if(redraw)
this.repaint();
},
setInstanceVisibility : function (tag, newState, redraw) {
var instances = this._scene.modelInstances;
for (var inst in instances) {
if(tag == HOP_ALL) {
instances[inst].visible = newState;
}
else {
for (var tg in instances[inst].tags){
if(instances[inst].tags[tg] == tag)
instances[inst].visible = newState;
}
}
}
if(redraw)
this.repaint();
},
toggleInstanceVisibilityByName : function (name, redraw) {
var instances = this._scene.modelInstances;
if(name == HOP_ALL) {
for (var inst in instances)
instances[inst].visible = !instances[inst].visible;
}
else {
if(instances[name]) // if an instance with that name exists
instances[name].visible = !instances[name].visible;
}
if(redraw)
this.repaint();
},
toggleInstanceVisibility : function (tag, redraw) {
var instances = this._scene.modelInstances;
for (var inst in instances) {
if(tag == HOP_ALL)
{
instances[inst].visible = !instances[inst].visible;
}
else
{
for (var tg in instances[inst].tags){
if(instances[inst].tags[tg] == tag)
instances[inst].visible = !instances[inst].visible;
}
}
}
if(redraw)
this.repaint();
},
isInstanceVisibilityEnabledByName : function (name) {
var visibility = false;
var instances = this._scene.modelInstances;
if(!name || name==HOP_ALL) {
for (var inst in instances) {
if(instances[inst].visible){
visibility = true;
return visibility;
}
}
}
else {
if(instances[name]) { // if an instance with that name exists
if(instances[name].visible){
visibility = true;
return visibility;
}
}
}
return visibility;
},
isInstanceVisibilityEnabled : function (tag) {
var visibility = false;
var instances = this._scene.modelInstances;
for (var inst in instances) {
if(!tag || tag==HOP_ALL){
if(instances[inst].visible){
visibility = true;
return visibility;
}
}
else{
for (var tg in instances[inst].tags){
if(instances[inst].tags[tg] == tag){
if(instances[inst].visible){
visibility = true;
return visibility;
}
}
}
}
}
return visibility;
},
//-----------------------------------------------------------------------------
// spot visibility
setSpotVisibilityByName : function (name, newState, redraw) {
var spots = this._scene.spots;
if(name == HOP_ALL) {
for (var spt in spots)
spots[spt].visible = newState;
}
else {
if(spots[name]) // if an hotspot with that name exists
spots[name].visible = newState;
}
if(redraw)
this.repaint();
},
setSpotVisibility : function (tag, newState, redraw) {
var spots = this._scene.spots;
for (var spt in spots) {
if(tag == HOP_ALL)
{
spots[spt].visible = newState;
}
else
{
for (var tg in spots[spt].tags){
if(spots[spt].tags[tg] == tag)
spots[spt].visible = newState;
}
}
}
if(redraw)
this.repaint();
},
toggleSpotVisibilityByName : function (name, redraw) {
var spots = this._scene.spots;
if(name == HOP_ALL) {
for (var spt in spots)
spots[spt].visible = !spots[spt].visible;
}
else {
if(spots[name]) // if an hotspot with that name exists
spots[name].visible = !spots[name].visible;
}
if(redraw)
this.repaint();
},
toggleSpotVisibility : function (tag, redraw) {
var spots = this._scene.spots;
for (var spt in spots) {
if(tag == HOP_ALL)
{
spots[spt].visible = !spots[spt].visible;
}
else
{
for (var tg in spots[spt].tags){
if(spots[spt].tags[tg] == tag)
spots[spt].visible = !spots[spt].visible;
}
}
}
if(redraw)
this.repaint();
},
isSpotVisibilityEnabledByName : function (name) {
var visibility = false;
var spots = this._scene.spots;
if(!name || name==HOP_ALL) {
for (var spt in spots) {
if(spots[spt].visible){
visibility = true;
return visibility;
}
}
}
else {
if(spots[name]) { // if an hotspot with that name exists
if(spots[name].visible){
visibility = true;
return visibility;
}
}
}
return visibility;
},
isSpotVisibilityEnabled : function (tag) {
var visibility = false;
var spots = this._scene.spots;
for (var spt in spots) {
if(!tag || tag==HOP_ALL){
if(spots[spt].visible){
visibility = true;
return visibility;
}
}
else{
for (var tg in spots[spt].tags){
if(spots[spt].tags[tg] == tag){
if(spots[spt].visible){
visibility = true;
return visibility;
}
}
}
}
}
return visibility;
},
//-----------------------------------------------------------------------------
// sections
resetClippingXYZ: function() {
this._calculateBounding();
this._clipAxis = [0.0, 0.0, 0.0];
this._clipPoint = [0.0, 0.0, 0.0];
this.repaint();
},
setClippingXYZ: function(cx, cy, cz) {
this._calculateBounding();
this._clipAxis = [cx,cy,cz];
this.repaint();
},
setClippingX: function(cx) {
this._calculateBounding();
this._clipAxis[0] = cx;
this.repaint();
},
setClippingY: function(cy) {
this._calculateBounding();
this._clipAxis[1] = cy;
this.repaint();
},
setClippingZ: function(cz) {
this._calculateBounding();
this._clipAxis[2] = cz;
this.repaint();
},
getClippingX : function () {
return this._clipAxis[0];
},
getClippingY : function () {
return this._clipAxis[1];
},
getClippingZ : function () {
return this._clipAxis[2];
},
setClippingPointXYZabs: function(clx, cly, clz) {
this._calculateBounding();
this._clipPoint = [clx, cly, clz];
this.repaint();
},
setClippingPointXabs: function(clx) {
this._calculateBounding();
this._clipPoint[0] = clx;
this.repaint();
},
setClippingPointYabs: function(cly) {
this._calculateBounding();
this._clipPoint[1] = cly;
this.repaint();
},
setClippingPointZabs: function(clz) {
this._calculateBounding();
this._clipPoint[2] = clz;
this.repaint();
},
setClippingPointXYZ: function(clx, cly, clz) {
var nClipPoint = [0.0, 0.0, 0.0];
this._calculateBounding();
if(clx<0.0) clx=0.0; else if(clx>1.0) clx=1.0;
if(cly<0.0) cly=0.0; else if(cly>1.0) cly=1.0
if(clz<0.0) clz=0.0; else if(clz>1.0) clz=1.0;
nClipPoint[0] = this._sceneBboxMin[0] + clx * (this._sceneBboxMax[0] - this._sceneBboxMin[0]);
nClipPoint[1] = this._sceneBboxMin[1] + cly * (this._sceneBboxMax[1] - this._sceneBboxMin[1]);
nClipPoint[2] = this._sceneBboxMin[2] + clz * (this._sceneBboxMax[2] - this._sceneBboxMin[2]);
this._clipPoint = nClipPoint;
this.repaint();
},
setClippingPointX: function(clx) {
var nClipPoint = 0.0;
this._calculateBounding();
if(clx<0.0) clx=0.0; else if(clx>1.0) clx=1.0;
nClipPoint = this._sceneBboxMin[0] + clx * (this._sceneBboxMax[0] - this._sceneBboxMin[0]);
this._clipPoint[0] = nClipPoint;
this.repaint();
},
setClippingPointY: function(cly) {
var nClipPoint = 0.0;
this._calculateBounding();
if(cly<0.0) cly=0.0; else if(cly>1.0) cly=1.0;
nClipPoint = this._sceneBboxMin[1] + cly * (this._sceneBboxMax[1] - this._sceneBboxMin[1]);
this._clipPoint[1] = nClipPoint;
this.repaint();
},
setClippingPointZ: function(clz) {
var nClipPoint = 0.0;
this._calculateBounding();
if(clz<0.0) clz=0.0; else if(clz>1.0) clz=1.0;
nClipPoint = this._sceneBboxMin[2] + clz * (this._sceneBboxMax[2] - this._sceneBboxMin[2]);
this._clipPoint[2] = nClipPoint;
this.repaint();
},
_calculateBounding: function() {
var meshes = this._scene.meshes;
var instances = this._scene.modelInstances;
this._sceneBboxMin = SglVec3.maxNumber();
this._sceneBboxMax = SglVec3.minNumber();
this._sceneBboxCenter = [0.0, 0.0, 0.0];
this._sceneBboxDiag = 0.0;
var imin = [0.0, 0.0, 0.0];
var imax = [0.0, 0.0, 0.0];
for (var inst in instances) {
var mesh = meshes[instances[inst].mesh];
if((mesh)&&(mesh.renderable)&&(instances[inst].clippable)){
var instCenter = SglVec3.to4(mesh.renderable.datasetCenter,1);
instCenter = SglMat4.mul4(mesh.transform.matrix, instCenter);
instCenter = SglMat4.mul4(instances[inst].transform.matrix, instCenter);
instCenter = SglMat4.mul4(this._scene.space.transform.matrix, instCenter);
instCenter = SglVec4.to3(instCenter);
var radius = mesh.renderable.datasetRadius;
var vector111 = SglVec3.one();
vector111 = SglMat3.mul3(SglMat4.to33(mesh.transform.matrix), vector111);
vector111 = SglMat3.mul3(SglMat4.to33(instances[inst].transform.matrix), vector111);
vector111 = SglMat3.mul3(SglMat4.to33(this._scene.space.transform.matrix), vector111);
var scalefactor = SglVec3.length(vector111) / SglVec3.length([1,1,1]);
radius = radius*scalefactor;
imin[0] = instCenter[0] - radius;
imin[1] = instCenter[1] - radius;
imin[2] = instCenter[2] - radius;
imax[0] = instCenter[0] + radius;
imax[1] = instCenter[1] + radius;
imax[2] = instCenter[2] + radius;
if(imin[0] < this._sceneBboxMin[0]) this._sceneBboxMin[0] = imin[0];
if(imin[1] < this._sceneBboxMin[1]) this._sceneBboxMin[1] = imin[1];
if(imin[2] < this._sceneBboxMin[2]) this._sceneBboxMin[2] = imin[2];
if(imax[0] > this._sceneBboxMax[0]) this._sceneBboxMax[0] = imax[0];
if(imax[1] > this._sceneBboxMax[1]) this._sceneBboxMax[1] = imax[1];
if(imax[2] > this._sceneBboxMax[2]) this._sceneBboxMax[2] = imax[2];
}
}
this._sceneBboxCenter[0] = (this._sceneBboxMin[0] + this._sceneBboxMax[0]) / 2.0;
this._sceneBboxCenter[1] = (this._sceneBboxMin[1] + this._sceneBboxMax[1]) / 2.0;
this._sceneBboxCenter[2] = (this._sceneBboxMin[2] + this._sceneBboxMax[2]) / 2.0;
this._sceneBboxDiag = SglVec3.length([ this._sceneBboxMax[0]-this._sceneBboxMin[0], this._sceneBboxMax[1]-this._sceneBboxMin[1], this._sceneBboxMax[2]-this._sceneBboxMin[2]]);
},
setClippingRendermode: function(showPlanes, showBorder, borderSize, borderColor) {
this._calculateBounding();
this._scene.config.showClippingPlanes = showPlanes;
this._scene.config.showClippingBorder = showBorder;
if(borderSize>0.0)
this._scene.config.clippingBorderSize = borderSize;
if(borderColor)
this._scene.config.clippingBorderColor = borderColor;
this.repaint();
},
getClippingRendermode: function() {
var rendermode = [this._scene.config.showClippingPlanes, this._scene.config.showClippingBorder, this._scene.config.clippingBorderSize, this._scene.config.clippingBorderColor];
return rendermode;
},
resetClippingPlane : function () {
this._calculateBounding();
this._clipPlane = [0.0, 0.0, 0.0, 0.0];
this.repaint();
},
setClippingPlaneExplicit : function (axis, offset) {
this._calculateBounding();
this._clipPlane = [axis[0], axis[1], axis[2], offset];
this.repaint();
},
setClippingPlane : function (angleH, angleV, sign, delta, deltaabs) {
this._calculateBounding();
var axis;
var m = SglMat4.identity();
this._clipPlaneAH = angleH;
this._clipPlaneAV = angleV;
// horizontal angle
m = SglMat4.mul(m, SglMat4.rotationAngleAxis(sglDegToRad(angleH), [0.0, -1.0, 0.0]));
// vertical angle
m = SglMat4.mul(m, SglMat4.rotationAngleAxis(sglDegToRad(angleV), [0.0, 0.0, 1.0]));
axis = [sign*1.0, 0.0, 0.0, 1.0];
axis = SglMat4.mul4(m, axis);
var sceneOff = (this._sceneBboxDiag / 2.0) * (delta / 100.0);
if(typeof deltaabs !== "undefined")
sceneOff = deltaabs;
var position = [this._sceneBboxCenter[0] + (axis[0] * sceneOff), this._sceneBboxCenter[1] + (axis[1] * sceneOff), this._sceneBboxCenter[2] + (axis[2] * sceneOff)];
sceneOff = SglVec3.dot([axis[0], axis[1], axis[2]], position);
this._clipPlane = [axis[0], axis[1], axis[2], -sceneOff];
this.repaint();
},
//-----------------------------------------------------------------------------
// zoom
zoomIn: function() {
this.onMouseWheel(1);
},
zoomOut: function() {
this.onMouseWheel(-1);
},
//-----------------------------------------------------------------------------
// light
rotateLight: function(x, y) {
var dx = x * 2.0;
var dy = y * 2.0;
var dz = 0.0;
var r = Math.sqrt(dx*dx + dy*dy);
if(r >= 1) {
dx /= r;
dy /= r;
dz = 0.0;
} else {
dz = Math.sqrt(1 - r*r);
}
this._lightDirection = [-dx, -dy, -dz];
this.repaint();
},
setLight: function(dir) {
this._lightDirection = SglVec3.normalize([-dir[0], -dir[1], -dir[2]]);
this.repaint();
},
enableLightTrackball: function(on) {
this._movingLight = on;
if(on && !this._scene.space.sceneLighting) this._scene.space.sceneLighting = on;
this.repaint();
},
isLightTrackballEnabled: function() {
return this._movingLight;
},
//-----------------------------------------------------------------------------
// onHover
enableOnHover: function(on) {
this._onHover = on;
},
isOnHoverEnabled: function() {
return this._onHover;
},
//-----------------------------------------------------------------------------
// linear measure
enableMeasurementTool: function(on) {
if(on)
this._startMeasurement();
else
this._stopMeasurement();
},
isMeasurementToolEnabled: function() {
return this._isMeasuringDistance;
},
//-----------------------------------------------------------------------------
// point measure
enablePickpointMode: function(on) {
if(on)
this._startPickPoint();
else
this._stopPickPoint();
},
isPickpointModeEnabled: function() {
return this._isMeasuringPickpoint;
},
//-----------------------------------------------------------------------------
// measurements
isAnyMeasurementEnabled: function() {
return this._isMeasuring;
},
//-----------------------------------------------------------------------------
// camera type
toggleCameraType: function() {
if(this._scene.space.cameraType == "orthographic")
this._scene.space.cameraType = "perspective"
else
this._scene.space.cameraType = "orthographic"
this.repaint();
},
setCameraPerspective: function() {
this._scene.space.cameraType = "perspective";
this.repaint();
},
setCameraOrthographic: function() {
this._scene.space.cameraType = "orthographic";
this.repaint();
},
getCameraType : function () {
return this._scene.space.cameraType;
},
//-----------------------------------------------------------------------------
// trackball lock
toggleTrackballLock: function() {
this._scene.trackball.locked = !this._scene.trackball.locked;
},
setTrackballLock: function(newState) {
this._scene.trackball.locked = newState;
},
isTrackballLockEnabled: function() {
return this._scene.trackball.locked;
},
//-----------------------------------------------------------------------------
// lighting
enableSceneLighting: function(on) {
this._scene.space.sceneLighting = on;
if(!on && this._movingLight) this._movingLight = on;
this.repaint();
},
isSceneLightingEnabled: function() {
return this._scene.space.sceneLighting;
},
setInstanceLightingByName : function (name, newState, redraw) {
var instances = this._scene.modelInstances;
if(name == HOP_ALL) {
for (var inst in instances)
instances[inst].useLighting = newState;
}
else {
if(instances[name]) // if an instance with that name exists
instances[name].useLighting = newState;
}
if(redraw)
this.repaint();
},
setInstanceLighting : function (tag, newState, redraw) {
var instances = this._scene.modelInstances;
for (var inst in instances) {
if(tag == HOP_ALL) {
instances[inst].useLighting = newState;
}
else {
for (var tg in instances[inst].tags){
if(instances[inst].tags[tg] == tag)
instances[inst].useLighting = newState;
}
}
}
if(redraw)
this.repaint();
},
toggleInstanceLightingByName : function (name, redraw) {
var instances = this._scene.modelInstances;
if(name == HOP_ALL) {
for (var inst in instances)
instances[inst].useLighting = !instances[inst].useLighting;
}
else {
if(instances[name]) // if an instance with that name exists
instances[name].useLighting = !instances[name].useLighting;
}
if(redraw)
this.repaint();
},
toggleInstanceLighting : function (tag, redraw) {
var instances = this._scene.modelInstances;
for (var inst in instances) {
if(tag == HOP_ALL)
{
instances[inst].useLighting = !instances[inst].useLighting;
}
else
{
for (var tg in instances[inst].tags){
if(instances[inst].tags[tg] == tag)
instances[inst].useLighting = !instances[inst].useLighting;
}
}
}
if(redraw)
this.repaint();
},
isInstanceLightingEnabledByName : function (name) {
var Lighting = false;
var instances = this._scene.modelInstances;
if(!name || name==HOP_ALL) {
for (var inst in instances) {
if(instances[inst].useLighting){
Lighting = true;
return Lighting;
}
}
}
else {
if(instances[name]) { // if an instance with that name exists
if(instances[name].useLighting){
Lighting = true;
return Lighting;
}
}
}
return Lighting;
},
isInstanceLightingEnabled : function (tag) {
var Lighting = false;
var instances = this._scene.modelInstances;
for (var inst in instances) {
if(!tag || tag==HOP_ALL){
if(instances[inst].useLighting){
Lighting = true;
return Lighting;
}
}
else{
for (var tg in instances[inst].tags){
if(instances[inst].tags[tg] == tag){
if(instances[inst].useLighting){
Lighting = true;
return Lighting;
}
}
}
}
}
return Lighting;
}
}; // Presenter.prototype END
// export default Presenter;
// export {
// HOP_VERSION,
// HOP_ALL,
// HOP_DEBUGMODE,
// HOP_DEFAULTLIGHT,
// SGL_TRACKBALL_NO_ACTION,
// SGL_TRACKBALL_ROTATE,
// SGL_TRACKBALL_PAN,
// SGL_TRACKBALL_DOLLY,
// SGL_TRACKBALL_SCALE
// };