839 lines
26 KiB
JavaScript
839 lines
26 KiB
JavaScript
|
/**
|
||
|
* Generated by Verge3D Puzzles v.4.1.1
|
||
|
* Tue, 01 Nov 2022 06:09:12 GMT
|
||
|
* Prefer not editing this file as your changes may get overridden once Puzzles are saved.
|
||
|
* Check out https://www.soft8soft.com/docs/manual/en/introduction/Using-JavaScript.html
|
||
|
* for the information on how to add your own JavaScript to Verge3D apps.
|
||
|
*/
|
||
|
|
||
|
'use strict';
|
||
|
|
||
|
(function() {
|
||
|
|
||
|
// global variables/constants used by puzzles' functions
|
||
|
|
||
|
var LIST_NONE = '<none>';
|
||
|
|
||
|
var _pGlob = {};
|
||
|
|
||
|
_pGlob.objCache = {};
|
||
|
_pGlob.fadeAnnotations = true;
|
||
|
_pGlob.pickedObject = '';
|
||
|
_pGlob.hoveredObject = '';
|
||
|
_pGlob.mediaElements = {};
|
||
|
_pGlob.loadedFile = '';
|
||
|
_pGlob.states = [];
|
||
|
_pGlob.percentage = 0;
|
||
|
_pGlob.openedFile = '';
|
||
|
_pGlob.openedFileMeta = {};
|
||
|
_pGlob.xrSessionAcquired = false;
|
||
|
_pGlob.xrSessionCallbacks = [];
|
||
|
_pGlob.screenCoords = new v3d.Vector2();
|
||
|
_pGlob.intervalTimers = {};
|
||
|
_pGlob.customEvents = new v3d.EventDispatcher();
|
||
|
|
||
|
_pGlob.AXIS_X = new v3d.Vector3(1, 0, 0);
|
||
|
_pGlob.AXIS_Y = new v3d.Vector3(0, 1, 0);
|
||
|
_pGlob.AXIS_Z = new v3d.Vector3(0, 0, 1);
|
||
|
_pGlob.MIN_DRAG_SCALE = 10e-4;
|
||
|
_pGlob.SET_OBJ_ROT_EPS = 1e-8;
|
||
|
|
||
|
_pGlob.vec2Tmp = new v3d.Vector2();
|
||
|
_pGlob.vec2Tmp2 = new v3d.Vector2();
|
||
|
_pGlob.vec3Tmp = new v3d.Vector3();
|
||
|
_pGlob.vec3Tmp2 = new v3d.Vector3();
|
||
|
_pGlob.vec3Tmp3 = new v3d.Vector3();
|
||
|
_pGlob.vec3Tmp4 = new v3d.Vector3();
|
||
|
_pGlob.eulerTmp = new v3d.Euler();
|
||
|
_pGlob.eulerTmp2 = new v3d.Euler();
|
||
|
_pGlob.quatTmp = new v3d.Quaternion();
|
||
|
_pGlob.quatTmp2 = new v3d.Quaternion();
|
||
|
_pGlob.colorTmp = new v3d.Color();
|
||
|
_pGlob.mat4Tmp = new v3d.Matrix4();
|
||
|
_pGlob.planeTmp = new v3d.Plane();
|
||
|
_pGlob.raycasterTmp = new v3d.Raycaster();
|
||
|
|
||
|
var PL = v3d.PL = v3d.PL || {};
|
||
|
|
||
|
// a more readable alias for PL (stands for "Puzzle Logic")
|
||
|
v3d.puzzles = PL;
|
||
|
|
||
|
PL.procedures = PL.procedures || {};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
PL.execInitPuzzles = function(options) {
|
||
|
// always null, should not be available in "init" puzzles
|
||
|
var appInstance = null;
|
||
|
// app is more conventional than appInstance (used in exec script and app templates)
|
||
|
var app = null;
|
||
|
|
||
|
var _initGlob = {};
|
||
|
_initGlob.percentage = 0;
|
||
|
_initGlob.output = {
|
||
|
initOptions: {
|
||
|
fadeAnnotations: true,
|
||
|
useBkgTransp: false,
|
||
|
preserveDrawBuf: false,
|
||
|
useCompAssets: false,
|
||
|
useFullscreen: true,
|
||
|
useCustomPreloader: false,
|
||
|
preloaderStartCb: function() {},
|
||
|
preloaderProgressCb: function() {},
|
||
|
preloaderEndCb: function() {},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// provide the container's id to puzzles that need access to the container
|
||
|
_initGlob.container = options !== undefined && 'container' in options
|
||
|
? options.container : "";
|
||
|
|
||
|
|
||
|
|
||
|
// initSettings puzzle
|
||
|
_initGlob.output.initOptions.fadeAnnotations = true;
|
||
|
_initGlob.output.initOptions.useBkgTransp = true;
|
||
|
_initGlob.output.initOptions.preserveDrawBuf = false;
|
||
|
_initGlob.output.initOptions.useCompAssets = false;
|
||
|
_initGlob.output.initOptions.useFullscreen = true;
|
||
|
|
||
|
return _initGlob.output;
|
||
|
}
|
||
|
|
||
|
PL.init = function(appInstance, initOptions) {
|
||
|
|
||
|
// app is more conventional than appInstance (used in exec script and app templates)
|
||
|
var app = appInstance;
|
||
|
|
||
|
initOptions = initOptions || {};
|
||
|
|
||
|
if ('fadeAnnotations' in initOptions) {
|
||
|
_pGlob.fadeAnnotations = initOptions.fadeAnnotations;
|
||
|
}
|
||
|
|
||
|
this.procedures["EquipmentClick"] = EquipmentClick;
|
||
|
|
||
|
var Cliclk, flag, Logo, modetype;
|
||
|
|
||
|
// utility function envoked by almost all V3D-specific puzzles
|
||
|
// filter off some non-mesh types
|
||
|
function notIgnoredObj(obj) {
|
||
|
return obj.type !== 'AmbientLight' &&
|
||
|
obj.name !== '' &&
|
||
|
!(obj.isMesh && obj.isMaterialGeneratedMesh) &&
|
||
|
!obj.isAuxClippingMesh;
|
||
|
}
|
||
|
|
||
|
|
||
|
// utility function envoked by almost all V3D-specific puzzles
|
||
|
// find first occurence of the object by its name
|
||
|
function getObjectByName(objName) {
|
||
|
var objFound;
|
||
|
var runTime = _pGlob !== undefined;
|
||
|
objFound = runTime ? _pGlob.objCache[objName] : null;
|
||
|
|
||
|
if (objFound && objFound.name === objName)
|
||
|
return objFound;
|
||
|
|
||
|
if (appInstance.scene) {
|
||
|
appInstance.scene.traverse(function(obj) {
|
||
|
if (!objFound && notIgnoredObj(obj) && (obj.name == objName)) {
|
||
|
objFound = obj;
|
||
|
if (runTime) {
|
||
|
_pGlob.objCache[objName] = objFound;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
return objFound;
|
||
|
}
|
||
|
|
||
|
|
||
|
// utility function envoked by almost all V3D-specific puzzles
|
||
|
// retrieve all objects on the scene
|
||
|
function getAllObjectNames() {
|
||
|
var objNameList = [];
|
||
|
appInstance.scene.traverse(function(obj) {
|
||
|
if (notIgnoredObj(obj))
|
||
|
objNameList.push(obj.name)
|
||
|
});
|
||
|
return objNameList;
|
||
|
}
|
||
|
|
||
|
|
||
|
// utility function envoked by almost all V3D-specific puzzles
|
||
|
// retrieve all objects which belong to the group
|
||
|
function getObjectNamesByGroupName(targetGroupName) {
|
||
|
var objNameList = [];
|
||
|
appInstance.scene.traverse(function(obj){
|
||
|
if (notIgnoredObj(obj)) {
|
||
|
var groupNames = obj.groupNames;
|
||
|
if (!groupNames)
|
||
|
return;
|
||
|
for (var i = 0; i < groupNames.length; i++) {
|
||
|
var groupName = groupNames[i];
|
||
|
if (groupName == targetGroupName) {
|
||
|
objNameList.push(obj.name);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
return objNameList;
|
||
|
}
|
||
|
|
||
|
|
||
|
// utility function envoked by almost all V3D-specific puzzles
|
||
|
// process object input, which can be either single obj or array of objects, or a group
|
||
|
function retrieveObjectNames(objNames) {
|
||
|
var acc = [];
|
||
|
retrieveObjectNamesAcc(objNames, acc);
|
||
|
return acc.filter(function(name) {
|
||
|
return name;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function retrieveObjectNamesAcc(currObjNames, acc) {
|
||
|
if (typeof currObjNames == "string") {
|
||
|
acc.push(currObjNames);
|
||
|
} else if (Array.isArray(currObjNames) && currObjNames[0] == "GROUP") {
|
||
|
var newObj = getObjectNamesByGroupName(currObjNames[1]);
|
||
|
for (var i = 0; i < newObj.length; i++)
|
||
|
acc.push(newObj[i]);
|
||
|
} else if (Array.isArray(currObjNames) && currObjNames[0] == "ALL_OBJECTS") {
|
||
|
var newObj = getAllObjectNames();
|
||
|
for (var i = 0; i < newObj.length; i++)
|
||
|
acc.push(newObj[i]);
|
||
|
} else if (Array.isArray(currObjNames)) {
|
||
|
for (var i = 0; i < currObjNames.length; i++)
|
||
|
retrieveObjectNamesAcc(currObjNames[i], acc);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// updateTextObject puzzle
|
||
|
function updateTextObj(objSelector, text) {
|
||
|
var objNames = retrieveObjectNames(objSelector);
|
||
|
|
||
|
for (var i = 0; i < objNames.length; i++) {
|
||
|
var objName = objNames[i];
|
||
|
if (!objName) continue;
|
||
|
var obj = getObjectByName(objName);
|
||
|
if (!obj || !obj.geometry || !obj.geometry.cloneWithText)
|
||
|
continue;
|
||
|
obj.geometry = obj.geometry.cloneWithText(String(text));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// setActiveCamera puzzle
|
||
|
function setActiveCamera(camName) {
|
||
|
var camera = getObjectByName(camName);
|
||
|
if (!camera || !camera.isCamera || appInstance.getCamera() == camera)
|
||
|
return;
|
||
|
appInstance.setCamera(camera);
|
||
|
}
|
||
|
|
||
|
// setCameraParam puzzle
|
||
|
function setCameraParam(type, objSelector, param) {
|
||
|
|
||
|
var objNames = retrieveObjectNames(objSelector);
|
||
|
|
||
|
objNames.forEach(function(objName) {
|
||
|
if (!objName)
|
||
|
return;
|
||
|
|
||
|
var obj = getObjectByName(objName);
|
||
|
if (!obj || !obj.isCamera) return;
|
||
|
|
||
|
if (!(obj.isPerspectiveCamera || obj.isOrthographicCamera)) {
|
||
|
console.error('setCameraParam: Incompatible camera type, have to be perspective or orthographic');
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
let isSetOrbitParam = false;
|
||
|
switch (type) {
|
||
|
case 'ORBIT_MIN_DISTANCE_PERSP':
|
||
|
case 'ORBIT_MAX_DISTANCE_PERSP':
|
||
|
case 'ORBIT_MIN_ZOOM_ORTHO':
|
||
|
case 'ORBIT_MAX_ZOOM_ORTHO':
|
||
|
case 'ORBIT_MIN_VERTICAL_ANGLE':
|
||
|
case 'ORBIT_MAX_VERTICAL_ANGLE':
|
||
|
case 'ORBIT_MIN_HORIZONTAL_ANGLE':
|
||
|
case 'ORBIT_MAX_HORIZONTAL_ANGLE':
|
||
|
case 'ORBIT_ALLOW_TURNOVER':
|
||
|
isSetOrbitParam = true;
|
||
|
break;
|
||
|
}
|
||
|
let isSetControlsParam = (['ROTATION_SPEED', 'MOVEMENT_SPEED', 'ALLOW_PANNING', 'ALLOW_ZOOM', 'KEYBOARD_CONTROLS'].includes(type) || isSetOrbitParam);
|
||
|
if (isSetControlsParam) {
|
||
|
if (!obj.controls) {
|
||
|
console.error('setCameraParam: The "' + objName +'" camera has no controller');
|
||
|
return;
|
||
|
} else if (isSetOrbitParam && obj.controls.type != 'ORBIT') {
|
||
|
console.error('setCameraParam: Incompatible camera controller');
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch (type) {
|
||
|
case 'FIELD_OF_VIEW':
|
||
|
if (obj.isPerspectiveCamera) {
|
||
|
obj.fov = param;
|
||
|
obj.updateProjectionMatrix();
|
||
|
} else {
|
||
|
console.error('setCameraParam: Incompatible camera type, have to be perspective');
|
||
|
return;
|
||
|
}
|
||
|
break;
|
||
|
case 'ORTHO_SCALE':
|
||
|
if (obj.isOrthographicCamera) {
|
||
|
obj.zoom = param;
|
||
|
obj.updateProjectionMatrix();
|
||
|
} else {
|
||
|
console.error('setCameraParam: Incompatible camera type, have to be orthographic');
|
||
|
return;
|
||
|
}
|
||
|
break;
|
||
|
case 'ROTATION_SPEED':
|
||
|
obj.controls.rotateSpeed = param;
|
||
|
break;
|
||
|
case 'MOVEMENT_SPEED':
|
||
|
obj.controls.moveSpeed = param;
|
||
|
break;
|
||
|
case 'ALLOW_PANNING':
|
||
|
obj.controls.enablePan = param;
|
||
|
break;
|
||
|
case 'ALLOW_ZOOM':
|
||
|
obj.controls.enableZoom = param;
|
||
|
break;
|
||
|
case 'KEYBOARD_CONTROLS':
|
||
|
obj.controls.enableKeys = param;
|
||
|
break;
|
||
|
case 'ORBIT_MIN_DISTANCE_PERSP':
|
||
|
if (obj.isPerspectiveCamera) {
|
||
|
obj.controls.orbitMinDistance = param;
|
||
|
} else {
|
||
|
console.error('setCameraParam: Incompatible camera type, have to be perspective');
|
||
|
return;
|
||
|
}
|
||
|
break;
|
||
|
case 'ORBIT_MAX_DISTANCE_PERSP':
|
||
|
if (obj.isPerspectiveCamera) {
|
||
|
obj.controls.orbitMaxDistance = param;
|
||
|
} else {
|
||
|
console.error('setCameraParam: Incompatible camera type, have to be perspective');
|
||
|
return;
|
||
|
}
|
||
|
break;
|
||
|
case 'ORBIT_MIN_ZOOM_ORTHO':
|
||
|
if (obj.isOrthographicCamera) {
|
||
|
obj.controls.orbitMinZoom = param;
|
||
|
} else {
|
||
|
console.error('setCameraParam: Incompatible camera type, have to be orthographic');
|
||
|
return;
|
||
|
}
|
||
|
break;
|
||
|
case 'ORBIT_MAX_ZOOM_ORTHO':
|
||
|
if (obj.isOrthographicCamera) {
|
||
|
obj.controls.orbitMaxZoom = param;
|
||
|
} else {
|
||
|
console.error('setCameraParam: Incompatible camera type, have to be orthographic');
|
||
|
return;
|
||
|
}
|
||
|
break;
|
||
|
case 'ORBIT_MIN_VERTICAL_ANGLE':
|
||
|
obj.controls.orbitMinPolarAngle = v3d.MathUtils.degToRad(param);
|
||
|
break;
|
||
|
case 'ORBIT_MAX_VERTICAL_ANGLE':
|
||
|
obj.controls.orbitMaxPolarAngle = v3d.MathUtils.degToRad(param);
|
||
|
break;
|
||
|
case 'ORBIT_MIN_HORIZONTAL_ANGLE':
|
||
|
obj.controls.orbitMinAzimuthAngle = v3d.MathUtils.degToRad(param);
|
||
|
break;
|
||
|
case 'ORBIT_MAX_HORIZONTAL_ANGLE':
|
||
|
obj.controls.orbitMaxAzimuthAngle = v3d.MathUtils.degToRad(param);
|
||
|
break;
|
||
|
case 'ORBIT_ALLOW_TURNOVER':
|
||
|
obj.controls.orbitEnableTurnover = param;
|
||
|
break;
|
||
|
case 'CLIP_START':
|
||
|
obj.near = param;
|
||
|
obj.updateProjectionMatrix();
|
||
|
break;
|
||
|
case 'CLIP_END':
|
||
|
obj.far = param;
|
||
|
obj.updateProjectionMatrix();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (isSetControlsParam)
|
||
|
appInstance.enableControls();
|
||
|
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* mesh or multi-material object
|
||
|
*/
|
||
|
function isMeshObj(obj) {
|
||
|
if (obj.isMesh)
|
||
|
return true;
|
||
|
|
||
|
for (var i = 0; i < obj.children.length; i++) {
|
||
|
var child = obj.children[i];
|
||
|
if (child.isMesh && child.isMaterialGeneratedMesh)
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
function getObjectsFromCollect(obj, type, out) {
|
||
|
if (!notIgnoredObj(obj))
|
||
|
return;
|
||
|
|
||
|
switch (type) {
|
||
|
case 'ALL':
|
||
|
if (out.indexOf(obj.name) < 0)
|
||
|
out.push(obj.name);
|
||
|
break;
|
||
|
case 'ANNOTATION':
|
||
|
if (obj.isAnnotation && out.indexOf(obj.name) < 0)
|
||
|
out.push(obj.name);
|
||
|
break;
|
||
|
case 'BONE':
|
||
|
if (obj.isBone && out.indexOf(obj.name) < 0)
|
||
|
out.push(obj.name);
|
||
|
break;
|
||
|
case 'CAMERA':
|
||
|
if (obj.isCamera && out.indexOf(obj.name) < 0)
|
||
|
out.push(obj.name);
|
||
|
break;
|
||
|
case 'EMPTY':
|
||
|
if (!obj.isAnnotationControl && !obj.isBone && !obj.isCamera && !obj.isGroup &&
|
||
|
!obj.isLine && !obj.isLOD && !obj.isLight && !isMeshObj(obj) && !obj.isPoints &&
|
||
|
!obj.isScene && !obj.isSprite && out.indexOf(obj.name) < 0)
|
||
|
out.push(obj.name);
|
||
|
break;
|
||
|
case 'LIGHT':
|
||
|
if (obj.isLight && out.indexOf(obj.name) < 0)
|
||
|
out.push(obj.name);
|
||
|
break;
|
||
|
case 'MESH':
|
||
|
if (isMeshObj(obj) && out.indexOf(obj.name) < 0)
|
||
|
out.push(obj.name);
|
||
|
break;
|
||
|
default:
|
||
|
console.error('getObjectsFrom: Unknown object type: ' + type);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
for (var i = 0; i < obj.children.length; i++) {
|
||
|
var child = obj.children[i];
|
||
|
getObjectsFromCollect(child, type, out);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// getObjectsFrom puzzle
|
||
|
function getObjectsFrom(objSelector, type) {
|
||
|
|
||
|
var out = [];
|
||
|
|
||
|
var objNames = retrieveObjectNames(objSelector);
|
||
|
|
||
|
for (var i = 0; i < objNames.length; i++) {
|
||
|
var objName = objNames[i]
|
||
|
if (!objName)
|
||
|
continue;
|
||
|
|
||
|
var obj = getObjectByName(objName);
|
||
|
if (!obj)
|
||
|
continue;
|
||
|
|
||
|
getObjectsFromCollect(obj, type, out);
|
||
|
}
|
||
|
|
||
|
return out;
|
||
|
}
|
||
|
|
||
|
// show and hide puzzles
|
||
|
function changeVis(objSelector, bool) {
|
||
|
var objNames = retrieveObjectNames(objSelector);
|
||
|
|
||
|
for (var i = 0; i < objNames.length; i++) {
|
||
|
var objName = objNames[i]
|
||
|
if (!objName)
|
||
|
continue;
|
||
|
var obj = getObjectByName(objName);
|
||
|
if (!obj)
|
||
|
continue;
|
||
|
obj.visible = bool;
|
||
|
obj.resolveMultiMaterial().forEach(function(objR) {
|
||
|
objR.visible = bool;
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// utility functions envoked by the HTML puzzles
|
||
|
function getElements(ids, isParent) {
|
||
|
var elems = [];
|
||
|
if (Array.isArray(ids) && ids[0] != 'CONTAINER' && ids[0] != 'WINDOW' &&
|
||
|
ids[0] != 'DOCUMENT' && ids[0] != 'BODY' && ids[0] != 'QUERYSELECTOR') {
|
||
|
for (var i = 0; i < ids.length; i++)
|
||
|
elems.push(getElement(ids[i], isParent));
|
||
|
} else {
|
||
|
elems.push(getElement(ids, isParent));
|
||
|
}
|
||
|
return elems;
|
||
|
}
|
||
|
|
||
|
function getElement(id, isParent) {
|
||
|
var elem;
|
||
|
if (Array.isArray(id) && id[0] == 'CONTAINER') {
|
||
|
if (appInstance !== null) {
|
||
|
elem = appInstance.container;
|
||
|
} else if (typeof _initGlob !== 'undefined') {
|
||
|
// if we are on the initialization stage, we still can have access
|
||
|
// to the container element
|
||
|
var id = _initGlob.container;
|
||
|
if (isParent) {
|
||
|
elem = parent.document.getElementById(id);
|
||
|
} else {
|
||
|
elem = document.getElementById(id);
|
||
|
}
|
||
|
}
|
||
|
} else if (Array.isArray(id) && id[0] == 'WINDOW') {
|
||
|
if (isParent)
|
||
|
elem = parent;
|
||
|
else
|
||
|
elem = window;
|
||
|
} else if (Array.isArray(id) && id[0] == 'DOCUMENT') {
|
||
|
if (isParent)
|
||
|
elem = parent.document;
|
||
|
else
|
||
|
elem = document;
|
||
|
} else if (Array.isArray(id) && id[0] == 'BODY') {
|
||
|
if (isParent)
|
||
|
elem = parent.document.body;
|
||
|
else
|
||
|
elem = document.body;
|
||
|
} else if (Array.isArray(id) && id[0] == 'QUERYSELECTOR') {
|
||
|
if (isParent)
|
||
|
elem = parent.document.querySelector(id);
|
||
|
else
|
||
|
elem = document.querySelector(id);
|
||
|
} else {
|
||
|
if (isParent)
|
||
|
elem = parent.document.getElementById(id);
|
||
|
else
|
||
|
elem = document.getElementById(id);
|
||
|
}
|
||
|
return elem;
|
||
|
}
|
||
|
|
||
|
// setHTMLElemAttribute puzzle
|
||
|
function setHTMLElemAttribute(attr, value, ids, isParent) {
|
||
|
var elems = getElements(ids, isParent);
|
||
|
for (var i = 0; i < elems.length; i++) {
|
||
|
var elem = elems[i];
|
||
|
if (!elem) continue;
|
||
|
|
||
|
if ((attr == 'href' || attr == 'src') && value instanceof Promise) {
|
||
|
// resolve promise value for url-based attributes
|
||
|
value.then(function(response) {
|
||
|
elem[attr] = response;
|
||
|
});
|
||
|
} else {
|
||
|
elem[attr] = value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// getEntityByName puzzle
|
||
|
function getEntityByName(name, getWhat) {
|
||
|
switch (getWhat) {
|
||
|
case 'OBJECT':
|
||
|
case 'ANIMATION':
|
||
|
case 'MATERIAL':
|
||
|
return name;
|
||
|
case 'GROUP':
|
||
|
return ['GROUP', name];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Describe this function...
|
||
|
function EquipmentClick(Cliclk) {
|
||
|
flag = !flag;
|
||
|
if (flag) {
|
||
|
setHTMLElemAttribute('rel', _pGlob.hoveredObject, 'V3DData', true);
|
||
|
changeVis(getEntityByName(String(_pGlob.hoveredObject) + '-Text', 'OBJECT'), true);
|
||
|
changeVis(getEntityByName(String(_pGlob.hoveredObject) + '-Num', 'OBJECT'), true);
|
||
|
} else {
|
||
|
setHTMLElemAttribute('rel', _pGlob.hoveredObject, 'V3DData', true);
|
||
|
changeVis(getEntityByName(String(_pGlob.hoveredObject) + '-Text', 'OBJECT'), false);
|
||
|
changeVis(getEntityByName(String(_pGlob.hoveredObject) + '-Num', 'OBJECT'), false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// outline puzzle
|
||
|
function outline(objSelector, doWhat) {
|
||
|
var objNames = retrieveObjectNames(objSelector);
|
||
|
|
||
|
if (!appInstance.postprocessing || !appInstance.postprocessing.outlinePass)
|
||
|
return;
|
||
|
var outlineArray = appInstance.postprocessing.outlinePass.selectedObjects;
|
||
|
for (var i = 0; i < objNames.length; i++) {
|
||
|
var objName = objNames[i];
|
||
|
var obj = getObjectByName(objName);
|
||
|
if (!obj)
|
||
|
continue;
|
||
|
if (doWhat == "ENABLE") {
|
||
|
if (outlineArray.indexOf(obj) == -1)
|
||
|
outlineArray.push(obj);
|
||
|
} else {
|
||
|
var index = outlineArray.indexOf(obj);
|
||
|
if (index > -1)
|
||
|
outlineArray.splice(index, 1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// utility function used by the whenClicked, whenHovered and whenDraggedOver puzzles
|
||
|
function initObjectPicking(callback, eventType, mouseDownUseTouchStart, mouseButtons) {
|
||
|
|
||
|
var elem = appInstance.renderer.domElement;
|
||
|
elem.addEventListener(eventType, pickListener);
|
||
|
if (v3d.PL.editorEventListeners)
|
||
|
v3d.PL.editorEventListeners.push([elem, eventType, pickListener]);
|
||
|
|
||
|
if (eventType == 'mousedown') {
|
||
|
|
||
|
var touchEventName = mouseDownUseTouchStart ? 'touchstart' : 'touchend';
|
||
|
elem.addEventListener(touchEventName, pickListener);
|
||
|
if (v3d.PL.editorEventListeners)
|
||
|
v3d.PL.editorEventListeners.push([elem, touchEventName, pickListener]);
|
||
|
|
||
|
} else if (eventType == 'dblclick') {
|
||
|
|
||
|
var prevTapTime = 0;
|
||
|
|
||
|
function doubleTapCallback(event) {
|
||
|
|
||
|
var now = new Date().getTime();
|
||
|
var timesince = now - prevTapTime;
|
||
|
|
||
|
if (timesince < 600 && timesince > 0) {
|
||
|
|
||
|
pickListener(event);
|
||
|
prevTapTime = 0;
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
|
||
|
prevTapTime = new Date().getTime();
|
||
|
}
|
||
|
|
||
|
var touchEventName = mouseDownUseTouchStart ? 'touchstart' : 'touchend';
|
||
|
elem.addEventListener(touchEventName, doubleTapCallback);
|
||
|
if (v3d.PL.editorEventListeners)
|
||
|
v3d.PL.editorEventListeners.push([elem, touchEventName, doubleTapCallback]);
|
||
|
}
|
||
|
|
||
|
var raycaster = new v3d.Raycaster();
|
||
|
|
||
|
function pickListener(event) {
|
||
|
|
||
|
// to handle unload in loadScene puzzle
|
||
|
if (!appInstance.getCamera())
|
||
|
return;
|
||
|
|
||
|
event.preventDefault();
|
||
|
|
||
|
var xNorm = 0, yNorm = 0;
|
||
|
if (event instanceof MouseEvent) {
|
||
|
if (mouseButtons && mouseButtons.indexOf(event.button) == -1)
|
||
|
return;
|
||
|
xNorm = event.offsetX / elem.clientWidth;
|
||
|
yNorm = event.offsetY / elem.clientHeight;
|
||
|
} else if (event instanceof TouchEvent) {
|
||
|
var rect = elem.getBoundingClientRect();
|
||
|
xNorm = (event.changedTouches[0].clientX - rect.left) / rect.width;
|
||
|
yNorm = (event.changedTouches[0].clientY - rect.top) / rect.height;
|
||
|
}
|
||
|
|
||
|
_pGlob.screenCoords.x = xNorm * 2 - 1;
|
||
|
_pGlob.screenCoords.y = -yNorm * 2 + 1;
|
||
|
raycaster.setFromCamera(_pGlob.screenCoords, appInstance.getCamera(true));
|
||
|
var objList = [];
|
||
|
appInstance.scene.traverse(function(obj){objList.push(obj);});
|
||
|
var intersects = raycaster.intersectObjects(objList, false);
|
||
|
callback(intersects, event);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function objectsIncludeObj(objNames, testedObjName) {
|
||
|
if (!testedObjName) return false;
|
||
|
|
||
|
for (var i = 0; i < objNames.length; i++) {
|
||
|
if (testedObjName == objNames[i]) {
|
||
|
return true;
|
||
|
} else {
|
||
|
// also check children which are auto-generated for multi-material objects
|
||
|
var obj = getObjectByName(objNames[i]);
|
||
|
if (obj && obj.type == "Group") {
|
||
|
for (var j = 0; j < obj.children.length; j++) {
|
||
|
if (testedObjName == obj.children[j].name) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// utility function used by the whenClicked, whenHovered, whenDraggedOver, and raycast puzzles
|
||
|
function getPickedObjectName(obj) {
|
||
|
// auto-generated from a multi-material object, use parent name instead
|
||
|
if (obj.isMesh && obj.isMaterialGeneratedMesh && obj.parent) {
|
||
|
return obj.parent.name;
|
||
|
} else {
|
||
|
return obj.name;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// whenHovered puzzle
|
||
|
initObjectPicking(function(intersects, event) {
|
||
|
|
||
|
var prevHovered = _pGlob.hoveredObject;
|
||
|
var currHovered = '';
|
||
|
|
||
|
// the event might happen before hover registration
|
||
|
_pGlob.objHoverInfo = _pGlob.objHoverInfo || [];
|
||
|
|
||
|
// search for closest hovered object
|
||
|
|
||
|
var lastIntersectIndex = Infinity;
|
||
|
_pGlob.objHoverInfo.forEach(function(el) {
|
||
|
var maxIntersects = el.xRay ? intersects.length : Math.min(1, intersects.length);
|
||
|
|
||
|
for (var i = 0; i < maxIntersects; i++) {
|
||
|
var obj = intersects[i].object;
|
||
|
var objName = getPickedObjectName(obj);
|
||
|
|
||
|
if (objectsIncludeObj(retrieveObjectNames(el.objSelector), objName) && i <= lastIntersectIndex) {
|
||
|
currHovered = objName;
|
||
|
lastIntersectIndex = i;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
if (prevHovered == currHovered) return;
|
||
|
|
||
|
// first - all "out" callbacks, then - all "over"
|
||
|
_pGlob.objHoverInfo.forEach(function(el) {
|
||
|
if (objectsIncludeObj(retrieveObjectNames(el.objSelector), prevHovered)) {
|
||
|
// ensure the correct value of the hoveredObject block
|
||
|
_pGlob.hoveredObject = prevHovered;
|
||
|
el.callbacks[1](event);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
_pGlob.objHoverInfo.forEach(function(el) {
|
||
|
if (objectsIncludeObj(retrieveObjectNames(el.objSelector), currHovered)) {
|
||
|
// ensure the correct value of the hoveredObject block
|
||
|
_pGlob.hoveredObject = currHovered;
|
||
|
el.callbacks[0](event);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
_pGlob.hoveredObject = currHovered;
|
||
|
}, 'mousemove', false);
|
||
|
|
||
|
// whenHovered puzzle
|
||
|
function registerOnHover(objSelector, xRay, cbOver, cbOut) {
|
||
|
|
||
|
_pGlob.objHoverInfo = _pGlob.objHoverInfo || [];
|
||
|
|
||
|
_pGlob.objHoverInfo.push({
|
||
|
objSelector: objSelector,
|
||
|
callbacks: [cbOver, cbOut],
|
||
|
xRay: xRay
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// whenClicked puzzle
|
||
|
function registerOnClick(objSelector, xRay, doubleClick, mouseButtons, cbDo, cbIfMissedDo) {
|
||
|
|
||
|
// for AR/VR
|
||
|
_pGlob.objClickInfo = _pGlob.objClickInfo || [];
|
||
|
|
||
|
_pGlob.objClickInfo.push({
|
||
|
objSelector: objSelector,
|
||
|
callbacks: [cbDo, cbIfMissedDo]
|
||
|
});
|
||
|
|
||
|
initObjectPicking(function(intersects, event) {
|
||
|
|
||
|
var isPicked = false;
|
||
|
|
||
|
var maxIntersects = xRay ? intersects.length : Math.min(1, intersects.length);
|
||
|
|
||
|
for (var i = 0; i < maxIntersects; i++) {
|
||
|
var obj = intersects[i].object;
|
||
|
var objName = getPickedObjectName(obj);
|
||
|
var objNames = retrieveObjectNames(objSelector);
|
||
|
|
||
|
if (objectsIncludeObj(objNames, objName)) {
|
||
|
// save the object for the pickedObject block
|
||
|
_pGlob.pickedObject = objName;
|
||
|
isPicked = true;
|
||
|
cbDo(event);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!isPicked) {
|
||
|
_pGlob.pickedObject = '';
|
||
|
cbIfMissedDo(event);
|
||
|
}
|
||
|
|
||
|
}, doubleClick ? 'dblclick' : 'mousedown', false, mouseButtons);
|
||
|
}
|
||
|
|
||
|
|
||
|
updateTextObj('C1-2-Num', '100');
|
||
|
|
||
|
/* 限制摄像机 */
|
||
|
setActiveCamera('摄像机1');
|
||
|
setCameraParam('ALLOW_PANNING', '摄像机1', false);
|
||
|
setCameraParam('KEYBOARD_CONTROLS', '摄像机1', false);
|
||
|
setCameraParam('ROTATION_SPEED', '摄像机1', 0);
|
||
|
setCameraParam('FIELD_OF_VIEW', '摄像机1', 10);
|
||
|
Logo = getObjectsFrom(['GROUP', 'heighLight'], 'ALL');
|
||
|
modetype = 'free';
|
||
|
|
||
|
changeVis(['GROUP', 'RouteAndLogo'], false);
|
||
|
changeVis(['GROUP', 'EditNumber'], false);
|
||
|
|
||
|
registerOnHover(Logo, false, function() {
|
||
|
outline(_pGlob.hoveredObject, 'ENABLE');
|
||
|
}, function() {
|
||
|
outline(_pGlob.hoveredObject, 'DISABLE');
|
||
|
});
|
||
|
|
||
|
registerOnClick(Logo, false, false, [0,1,2], function() {
|
||
|
EquipmentClick(_pGlob.pickedObject);
|
||
|
}, function() {});
|
||
|
|
||
|
if (modetype == 'Free') {
|
||
|
}
|
||
|
if (modetype == 'Free') {
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
} // end of PL.init function
|
||
|
|
||
|
})(); // end of closure
|
||
|
|
||
|
/* ================================ end of code ============================= */
|