1035 lines
31 KiB
JavaScript
1035 lines
31 KiB
JavaScript
/**
|
|
* Generated by Verge3D Puzzles v.2.12.5
|
|
* Sat Jun 08 2019 00:30:36 GMT+0200 (Mitteleuropäische Sommerzeit)
|
|
* Do not edit this file - your changes may get overridden when Puzzles are saved.
|
|
* Refer to https://www.soft8soft.com/docs/manual/en/introduction/Using-JavaScript.html
|
|
* for information on how to add your own JavaScript to Verge3D apps.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
(function() {
|
|
|
|
// global variables/constants used by puzzles' functions
|
|
var _pGlob = {};
|
|
|
|
_pGlob.objCache = {};
|
|
_pGlob.fadeAnnotations = true;
|
|
_pGlob.objClickCallbacks = [];
|
|
_pGlob.pickedObject = '';
|
|
_pGlob.objHoverCallbacks = [];
|
|
_pGlob.hoveredObject = '';
|
|
_pGlob.objMovementInfos = {};
|
|
_pGlob.objDragOverCallbacks = [];
|
|
_pGlob.objDragOverInfoByBlock = {}
|
|
_pGlob.dragMoveOrigins = {};
|
|
_pGlob.dragScaleOrigins = {};
|
|
_pGlob.mediaElements = {};
|
|
_pGlob.loadedFiles = {};
|
|
_pGlob.loadedFile = '';
|
|
_pGlob.animMixerCallbacks = [];
|
|
_pGlob.arHitPoint = new v3d.Vector3(0, 0, 0);
|
|
_pGlob.states = [];
|
|
_pGlob.percentage = 0;
|
|
_pGlob.animateParamUpdate = null;
|
|
_pGlob.openedFile = '';
|
|
_pGlob.xrSessionAcquired = false;
|
|
_pGlob.xrSessionCallbacks = [];
|
|
_pGlob.screenCoords = new v3d.Vector2();
|
|
|
|
_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.vec2Tmp = new v3d.Vector2();
|
|
_pGlob.vec2Tmp2 = new v3d.Vector2();
|
|
_pGlob.vec3Tmp = new v3d.Vector3();
|
|
_pGlob.vec3Tmp2 = new v3d.Vector3();
|
|
_pGlob.quatTmp = new v3d.Quaternion();
|
|
_pGlob.quatTmp2 = new v3d.Quaternion();
|
|
_pGlob.mat4Tmp = new v3d.Matrix4();
|
|
_pGlob.planeTmp = new v3d.Plane();
|
|
_pGlob.raycasterTmp = new v3d.Raycaster();
|
|
_pGlob.timers = {};
|
|
|
|
var _pPhysics = {};
|
|
|
|
_pPhysics.syncList = [];
|
|
|
|
// internal info
|
|
_pPhysics.collisionData = [];
|
|
|
|
// goes to collision callback
|
|
_pPhysics.collisionInfo = {
|
|
objectA: '',
|
|
objectB: '',
|
|
distance: 0,
|
|
positionOnA: [0, 0, 0],
|
|
positionOnB: [0, 0, 0],
|
|
normalOnB: [0, 0, 0]
|
|
};
|
|
|
|
var PL = v3d.PL = v3d.PL || {};
|
|
|
|
PL.legacyMode = false;
|
|
|
|
PL.execInitPuzzles = function() {
|
|
|
|
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() {},
|
|
}
|
|
}
|
|
var ctrlInit, cinitx, cinity, cinitz;
|
|
|
|
|
|
// addHTMLElement puzzle
|
|
function addHTMLElement(elemType, id) {
|
|
var elem = document.createElement(elemType);
|
|
document.body.appendChild(elem);
|
|
elem.id = id;
|
|
elem.style.position = "absolute";
|
|
}
|
|
|
|
|
|
|
|
// utility functions envoked by the HTML puzzles
|
|
function getElements(ids, isParent) {
|
|
var elems = [];
|
|
if (Array.isArray(ids) && ids[0] != "WINDOW" && ids[0] != "DOCUMENT" && ids[0] != "BODY") {
|
|
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] == "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 (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;
|
|
elem[attr] = value;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// setHTMLElemStyle puzzle
|
|
function setHTMLElemStyle(prop, value, ids, isParent) {
|
|
var elems = getElements(ids, isParent);
|
|
for (var i = 0; i < elems.length; i++) {
|
|
var elem = elems[i];
|
|
if (!elem || !elem.style)
|
|
continue;
|
|
elem.style[prop] = value;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
addHTMLElement('input', 'lightness');
|
|
setHTMLElemAttribute('type', 'range', 'lightness', false);
|
|
|
|
|
|
// 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 = false;
|
|
|
|
ctrlInit;
|
|
|
|
addHTMLElement('input', 'hue');
|
|
setHTMLElemAttribute('type', 'range', 'hue', false);
|
|
|
|
addHTMLElement('input', 'saturation');
|
|
setHTMLElemAttribute('type', 'range', 'saturation', false);
|
|
|
|
setHTMLElemStyle('backgroundColor', 'rgb(127,127,127)', ["BODY"], false);
|
|
cinitx = 0;
|
|
cinity = 0;
|
|
cinitz = 0;
|
|
|
|
return _initGlob.output;
|
|
}
|
|
|
|
PL.init = function(appInstance, initOptions) {
|
|
|
|
initOptions = initOptions || {};
|
|
|
|
if ('fadeAnnotations' in initOptions) {
|
|
_pGlob.fadeAnnotations = initOptions.fadeAnnotations;
|
|
}
|
|
var distZ, r, g, b, stepY, distY, dragging, distX, inboundStepper, maxDist, sat, hue, value;
|
|
|
|
|
|
// 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;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
|
|
// 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 = typeof _pGlob != "undefined";
|
|
objFound = runTime ? _pGlob.objCache[objName] : null;
|
|
if (objFound && objFound.name == objName)
|
|
return objFound;
|
|
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 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
|
|
// filter off some non-mesh types
|
|
function notIgnoredObj(obj) {
|
|
return (obj.type != "Scene" && obj.type != "AmbientLight" &&
|
|
obj.name != "" && !(obj.isMesh && obj.isMaterialGeneratedMesh));
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
function swizzleValueSign(newAxis, value) {
|
|
newAxis = newAxis.toLowerCase();
|
|
|
|
if (newAxis == 'z') {
|
|
if (typeof value == 'number')
|
|
return -value
|
|
else if (typeof value == 'string' && value != '' && value != "''" && value != '""')
|
|
return String(-Number(value));
|
|
else
|
|
return value;
|
|
} else
|
|
return value;
|
|
}
|
|
|
|
function swizzleVec3(vec, isScale) {
|
|
|
|
var dest = []
|
|
|
|
dest[0] = vec[0];
|
|
dest[1] = vec[2];
|
|
dest[2] = isScale ? vec[1] : swizzleValueSign('z', vec[1])
|
|
|
|
return dest;
|
|
}
|
|
|
|
|
|
// getObjTransform puzzle
|
|
function getObjTransform(objName, mode, coord) {
|
|
if (!objName)
|
|
return;
|
|
var obj = getObjectByName(objName);
|
|
if (!obj)
|
|
return;
|
|
if (mode == "rotation")
|
|
return swizzleValueSign(coord, obj[mode][coord] * 180/Math.PI);
|
|
else if (mode == 'position')
|
|
return swizzleValueSign(coord, obj[mode][coord]);
|
|
else
|
|
return obj[mode][coord];
|
|
}
|
|
|
|
|
|
|
|
// getObjectMaterial puzzle
|
|
function getObjectMaterial(objNames) {
|
|
objNames = retrieveObjectNames(objNames);
|
|
if (!objNames)
|
|
return '';
|
|
for (var i = 0; i < objNames.length; i++) {
|
|
var objName = objNames[i]
|
|
if (!objName)
|
|
continue;
|
|
var obj = getObjectByName(objName);
|
|
if (!obj)
|
|
continue;
|
|
if (obj.material && typeof obj.material.name == "string")
|
|
return obj.material.name;
|
|
}
|
|
return '';
|
|
}
|
|
|
|
|
|
|
|
// assignMaterial puzzle
|
|
function assignMat(objNames, matName) {
|
|
objNames = retrieveObjectNames(objNames);
|
|
if (!objNames || !matName)
|
|
return;
|
|
var mat = v3d.SceneUtils.getMaterialByName(appInstance, matName);
|
|
if (!mat)
|
|
return;
|
|
for (var i = 0; i < objNames.length; i++) {
|
|
var objName = objNames[i];
|
|
if (!objName)
|
|
continue;
|
|
var obj = getObjectByName(objName);
|
|
if (obj)
|
|
obj.material = mat;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// utility function used by the whenClicked, whenHovered and whenDraggedOver puzzles
|
|
function initObjectPicking(callback, eventType, mouseDownUseTouchStart) {
|
|
|
|
var elem = appInstance.container;
|
|
elem.addEventListener(eventType, pickListener);
|
|
if (eventType == "mousedown") {
|
|
var touchEventName = mouseDownUseTouchStart ? "touchstart" : "touchend";
|
|
elem.addEventListener(touchEventName, pickListener);
|
|
}
|
|
|
|
var raycaster = new v3d.Raycaster();
|
|
function pickListener(event) {
|
|
event.preventDefault();
|
|
|
|
var xNorm = 0, yNorm = 0;
|
|
if (event instanceof MouseEvent) {
|
|
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.camera);
|
|
var objList = [];
|
|
appInstance.scene.traverse(function(obj){objList.push(obj);});
|
|
var intersects = raycaster.intersectObjects(objList);
|
|
if (intersects.length > 0) {
|
|
var obj = intersects[0].object;
|
|
callback(obj, event);
|
|
} else {
|
|
callback(null, event);
|
|
}
|
|
}
|
|
}
|
|
|
|
// utility function used by the whenDraggedOver puzzles
|
|
function fireObjectPickingCallbacks(objName, source, index, cbParam) {
|
|
for (var i = 0; i < source.length; i++) {
|
|
var cb = source[i];
|
|
if (objectsIncludeObj([cb[0]], objName)) {
|
|
cb[index](cbParam);
|
|
}
|
|
}
|
|
}
|
|
|
|
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 and whenDraggedOver 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;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// whenClicked puzzle
|
|
initObjectPicking(function(obj) {
|
|
|
|
// save the object for the pickedObject block
|
|
_pGlob.pickedObject = obj ? getPickedObjectName(obj) : '';
|
|
|
|
_pGlob.objClickCallbacks.forEach(function(el) {
|
|
var isPicked = obj && objectsIncludeObj(el.objNames, getPickedObjectName(obj));
|
|
el.callbacks[isPicked ? 0 : 1]();
|
|
});
|
|
}, 'mousedown');
|
|
|
|
|
|
|
|
// whenClicked puzzle
|
|
function registerOnClick(objNames, cbDo, cbIfMissedDo) {
|
|
objNames = retrieveObjectNames(objNames) || [];
|
|
var objNamesFiltered = objNames.filter(function(name) {
|
|
return name;
|
|
});
|
|
_pGlob.objClickCallbacks.push({
|
|
objNames: objNamesFiltered,
|
|
callbacks: [cbDo, cbIfMissedDo]
|
|
});
|
|
}
|
|
|
|
|
|
|
|
function intersectPlaneCSS(plane, cssX, cssY, dest) {
|
|
var coords = _pGlob.vec2Tmp;
|
|
var rc = _pGlob.raycasterTmp;
|
|
coords.x = (cssX / appInstance.getWidth()) * 2 - 1;
|
|
coords.y = - (cssY / appInstance.getHeight()) * 2 + 1;
|
|
rc.setFromCamera(coords, appInstance.camera);
|
|
return rc.ray.intersectPlane(plane, dest);
|
|
}
|
|
|
|
|
|
|
|
// dragMove puzzle
|
|
function dragMove(objNames, mode, blockId, parentDragOverBlockId) {
|
|
if (!appInstance.camera) return;
|
|
|
|
objNames = retrieveObjectNames(objNames);
|
|
if (!objNames) return;
|
|
|
|
var info = _pGlob.objDragOverInfoByBlock[parentDragOverBlockId];
|
|
if (!info) return;
|
|
|
|
var draggedObj = getObjectByName(info.draggedObjName);
|
|
if (!draggedObj) return;
|
|
|
|
if (!(blockId in _pGlob.dragMoveOrigins)) {
|
|
_pGlob.dragMoveOrigins[blockId] = [];
|
|
}
|
|
var posOrigins = _pGlob.dragMoveOrigins[blockId];
|
|
var lenDiff = objNames.length - posOrigins.length;
|
|
for (var i = 0; i < lenDiff; i++) {
|
|
posOrigins.push(new v3d.Vector3());
|
|
}
|
|
|
|
for (var i = 0; i < objNames.length; i++) {
|
|
var obj = getObjectByName(objNames[i]);
|
|
var posOrigin = posOrigins[i];
|
|
|
|
if (!info.isMoved) {
|
|
// the object position before the first move is used as an initial value
|
|
posOrigin.copy(obj.position);
|
|
}
|
|
|
|
if (mode == "X" || mode == "Y" || mode == "Z") {
|
|
var axis = mode == "X" ? _pGlob.AXIS_X : (mode == "Y" ? _pGlob.AXIS_Y : _pGlob.AXIS_Z);
|
|
var coord = mode == "X" ? "x" : (mode == "Y" ? "y" : "z");
|
|
|
|
var planeNor = appInstance.camera.getWorldDirection(_pGlob.vec3Tmp);
|
|
planeNor.cross(axis).cross(axis);
|
|
var plane = _pGlob.planeTmp.setFromNormalAndCoplanarPoint(planeNor, draggedObj.position);
|
|
|
|
var p0 = intersectPlaneCSS(plane, info.downX, info.downY, _pGlob.vec3Tmp);
|
|
var p1 = intersectPlaneCSS(plane, info.currX, info.currY, _pGlob.vec3Tmp2);
|
|
if (p0 && p1) {
|
|
obj.position[coord] = posOrigin[coord] + p1[coord] - p0[coord];
|
|
}
|
|
} else if (mode == "XY" || mode == "XZ" || mode == "YZ") {
|
|
var normal = mode == "XY" ? _pGlob.AXIS_Z : (mode == "XZ" ? _pGlob.AXIS_Y : _pGlob.AXIS_X);
|
|
var coord0 = mode == "XY" ? "x" : (mode == "XZ" ? "x" : "y");
|
|
var coord1 = mode == "XY" ? "y" : (mode == "XZ" ? "z" : "z");
|
|
|
|
var plane = _pGlob.planeTmp.setFromNormalAndCoplanarPoint(normal, draggedObj.position);
|
|
|
|
var p0 = intersectPlaneCSS(plane, info.downX, info.downY, _pGlob.vec3Tmp);
|
|
var p1 = intersectPlaneCSS(plane, info.currX, info.currY, _pGlob.vec3Tmp2);
|
|
if (p0 && p1) {
|
|
obj.position[coord0] = posOrigin[coord0] + p1[coord0] - p0[coord0];
|
|
obj.position[coord1] = posOrigin[coord1] + p1[coord1] - p0[coord1];
|
|
}
|
|
} else if (mode == "XYZ") {
|
|
var planeNor = appInstance.camera.getWorldDirection(_pGlob.vec3Tmp);
|
|
var plane = _pGlob.planeTmp.setFromNormalAndCoplanarPoint(planeNor, draggedObj.position);
|
|
|
|
var p0 = intersectPlaneCSS(plane, info.downX, info.downY, _pGlob.vec3Tmp);
|
|
var p1 = intersectPlaneCSS(plane, info.currX, info.currY, _pGlob.vec3Tmp2);
|
|
if (p0 && p1) {
|
|
obj.position.addVectors(posOrigin, p1).sub(p0);
|
|
}
|
|
}
|
|
obj.updateMatrixWorld(true);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// distanceBetweenObjects puzzle
|
|
function getDistanceBetweenObjects(objName1, objName2) {
|
|
if (!objName1 || !objName2)
|
|
return;
|
|
var obj1 = getObjectByName(objName1);
|
|
var obj2 = getObjectByName(objName2);
|
|
if (!obj1 || !obj2)
|
|
return;
|
|
return obj1.getWorldPosition(_pGlob.vec3Tmp).distanceTo(obj2.getWorldPosition(_pGlob.vec3Tmp2));
|
|
}
|
|
|
|
|
|
|
|
// applyObjLocalTransform puzzle
|
|
function applyObjLocalTransform(objNames, mode, x, y, z) {
|
|
|
|
objNames = retrieveObjectNames(objNames);
|
|
if (!objNames) return;
|
|
|
|
var defValue = mode == "scale" ? 1 : 0;
|
|
if (typeof x != "number") x = defValue;
|
|
if (typeof y != "number") y = defValue;
|
|
if (typeof z != "number") z = defValue;
|
|
|
|
var inVec = swizzleVec3([x,y,z], mode == 'scale');
|
|
|
|
for (var i = 0; i < objNames.length; i++) {
|
|
var objName = objNames[i];
|
|
if (!objName) continue;
|
|
|
|
var obj = getObjectByName(objName);
|
|
if (!obj) continue;
|
|
|
|
// don't swizzle values for cameras, their local space happens
|
|
// to be the same as for Blender/Max cameras, bcz their different
|
|
// rest orientation balances difference in coordinate systems
|
|
var useSwizzled = !obj.isCamera;
|
|
var xVal = useSwizzled ? inVec[0] : x;
|
|
var yVal = useSwizzled ? inVec[1] : y;
|
|
var zVal = useSwizzled ? inVec[2] : z;
|
|
|
|
switch (mode) {
|
|
case "position":
|
|
if (_pGlob.xrSessionAcquired && obj.isCamera) {
|
|
v3d.WebVRUtils.translateVRCamera(obj, _pGlob.AXIS_X, xVal);
|
|
v3d.WebVRUtils.translateVRCamera(obj, _pGlob.AXIS_Y, yVal);
|
|
v3d.WebVRUtils.translateVRCamera(obj, _pGlob.AXIS_Z, zVal);
|
|
} else {
|
|
obj.translateX(xVal);
|
|
obj.translateY(yVal);
|
|
obj.translateZ(zVal);
|
|
}
|
|
break;
|
|
case "rotation":
|
|
if (_pGlob.xrSessionAcquired && obj.isCamera) {
|
|
v3d.WebVRUtils.rotateVRCamera(obj, _pGlob.AXIS_X, v3d.Math.degToRad(xVal));
|
|
v3d.WebVRUtils.rotateVRCamera(obj, _pGlob.AXIS_Y, v3d.Math.degToRad(yVal));
|
|
v3d.WebVRUtils.rotateVRCamera(obj, _pGlob.AXIS_Z, v3d.Math.degToRad(zVal));
|
|
} else {
|
|
obj.rotateX(v3d.Math.degToRad(xVal));
|
|
obj.rotateY(v3d.Math.degToRad(yVal));
|
|
obj.rotateZ(v3d.Math.degToRad(zVal));
|
|
}
|
|
break;
|
|
case "scale":
|
|
obj.scale.x *= xVal;
|
|
obj.scale.y *= yVal;
|
|
obj.scale.z *= zVal;
|
|
break;
|
|
}
|
|
|
|
obj.updateMatrixWorld(true);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// callJSFunction puzzle
|
|
function getJSFunction(funcName) {
|
|
var jsFunc = appInstance.ExternalInterface[funcName];
|
|
if (typeof jsFunc == "function")
|
|
return jsFunc;
|
|
else
|
|
return function() {};
|
|
}
|
|
|
|
|
|
|
|
function eventGetOffsetCoords(e, touchId, dest) {
|
|
if (e instanceof MouseEvent) {
|
|
dest.set(e.offsetX, e.offsetY);
|
|
} else if (window.TouchEvent && e instanceof TouchEvent) {
|
|
var rect = e.target.getBoundingClientRect();
|
|
var touches = e.touches;
|
|
if (e.type == "touchstart" || e.type == "touchend" || e.type == "touchmove") {
|
|
touches = e.changedTouches;
|
|
}
|
|
|
|
var touch = touches[0];
|
|
for (var i = 0; i < touches.length; i++) {
|
|
if (touches[i].identifier == touchId) {
|
|
touch = touches[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
dest.set(touch.clientX - rect.left, touch.clientY - rect.top);
|
|
}
|
|
return dest;
|
|
}
|
|
|
|
|
|
function eventTouchIdGetFirst(e) {
|
|
if (e instanceof MouseEvent) {
|
|
return -1;
|
|
} else if (window.TouchEvent && e instanceof TouchEvent) {
|
|
if (e.type == "touchstart" || e.type == "touchend" || e.type == "touchmove") {
|
|
return e.changedTouches[0].identifier;
|
|
} else {
|
|
return e.touches[0].identifier;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
function eventTouchIdChangedFilter(e, touchId) {
|
|
if (window.TouchEvent && e instanceof TouchEvent) {
|
|
if (e.type == "touchstart" || e.type == "touchend" || e.type == "touchmove") {
|
|
var isChanged = false;
|
|
for (var i = 0; i < e.changedTouches.length; i++) {
|
|
if (e.changedTouches[i].identifier == touchId) {
|
|
isChanged = true;
|
|
break;
|
|
}
|
|
}
|
|
return isChanged;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
function initDragOverInfo() {
|
|
return {
|
|
draggedObjName: '',
|
|
downX: 0, downY: 0,
|
|
prevX: 0, prevY: 0,
|
|
currX: 0, currY: 0,
|
|
isDowned: false,
|
|
isMoved: false,
|
|
touchId: -1
|
|
};
|
|
}
|
|
|
|
|
|
// whenDraggedOver puzzle
|
|
initObjectPicking(function(obj, downEvent) {
|
|
if (!obj) {
|
|
return;
|
|
}
|
|
|
|
var objName = getPickedObjectName(obj);
|
|
fireObjectPickingCallbacks(objName, _pGlob.objDragOverCallbacks, 1,
|
|
{ downEvent: downEvent, draggedObjName: objName });
|
|
}, "mousedown", true);
|
|
|
|
|
|
|
|
// whenDraggedOver puzzle
|
|
function registerOnDrag(objNames, callback_start, callback_move, callback_drop, blockId) {
|
|
objNames = retrieveObjectNames(objNames);
|
|
if (!objNames)
|
|
return;
|
|
var cb = function(cbParam) {
|
|
|
|
if (appInstance.controls) {
|
|
appInstance.controls.enabled = false;
|
|
}
|
|
|
|
if (!(blockId in _pGlob.objDragOverInfoByBlock)) {
|
|
_pGlob.objDragOverInfoByBlock[blockId] = initDragOverInfo();
|
|
}
|
|
var info = _pGlob.objDragOverInfoByBlock[blockId];
|
|
|
|
// NOTE: don't use more than one pointing event, e.g. don't process
|
|
// some events related to multitouch actions
|
|
if (info.isDowned) {
|
|
return;
|
|
}
|
|
|
|
var touchId = eventTouchIdGetFirst(cbParam.downEvent);
|
|
var coords = eventGetOffsetCoords(cbParam.downEvent, touchId,
|
|
_pGlob.vec2Tmp);
|
|
|
|
info.downX = info.prevX = info.currX = coords.x;
|
|
info.downY = info.prevY = info.currY = coords.y;
|
|
info.touchId = touchId;
|
|
info.isDowned = true;
|
|
info.isMoved = false;
|
|
info.draggedObjName = cbParam.draggedObjName;
|
|
|
|
callback_start();
|
|
|
|
var elem = appInstance.container;
|
|
|
|
var moveCb = function(e) {
|
|
if (!eventTouchIdChangedFilter(e, info.touchId)) {
|
|
// don't handle events not intended for this particular touch
|
|
return;
|
|
}
|
|
|
|
var coords = eventGetOffsetCoords(e, info.touchId, _pGlob.vec2Tmp);
|
|
info.prevX = info.currX;
|
|
info.prevY = info.currY;
|
|
info.currX = coords.x;
|
|
info.currY = coords.y;
|
|
callback_move();
|
|
info.isMoved = true;
|
|
}
|
|
var upCb = function(e) {
|
|
if (!eventTouchIdChangedFilter(e, info.touchId)) {
|
|
// don't handle events not intended for this particular touch
|
|
return;
|
|
}
|
|
|
|
var coords = eventGetOffsetCoords(e, info.touchId, _pGlob.vec2Tmp);
|
|
info.currX = coords.x;
|
|
info.currY = coords.y;
|
|
info.prevX = info.currX;
|
|
info.prevY = info.currY;
|
|
callback_drop();
|
|
info.isDowned = false;
|
|
|
|
elem.removeEventListener("mousemove", moveCb, false);
|
|
elem.removeEventListener("touchmove", moveCb, false);
|
|
elem.removeEventListener("mouseup", upCb, false);
|
|
elem.removeEventListener("touchend", upCb, false);
|
|
if (appInstance.controls) {
|
|
appInstance.controls.enabled = true;
|
|
}
|
|
}
|
|
|
|
elem.addEventListener("mousemove", moveCb, false);
|
|
elem.addEventListener("touchmove", moveCb, false);
|
|
elem.addEventListener("mouseup", upCb, false);
|
|
elem.addEventListener("touchend", upCb, false);
|
|
}
|
|
for (var i = 0; i < objNames.length; i++) {
|
|
var objName = objNames[i];
|
|
if (!objName) continue;
|
|
_pGlob.objDragOverCallbacks.push([objName, cb]);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function matGetColors(matName) {
|
|
|
|
var mat = v3d.SceneUtils.getMaterialByName(appInstance, matName);
|
|
if (!mat) return [];
|
|
|
|
if (mat.isMeshNodeMaterial)
|
|
return Object.keys(mat.nodeRGBMap);
|
|
else if (mat.isMeshStandardMaterial)
|
|
return ['color', 'emissive'];
|
|
else
|
|
return []
|
|
}
|
|
|
|
|
|
// setMaterialColor puzzle
|
|
function setMaterialColor(matName, colName, r, g, b) {
|
|
var colors = matGetColors(matName);
|
|
|
|
if (colors.indexOf(colName) < 0) return;
|
|
|
|
var mats = v3d.SceneUtils.getMaterialsByName(appInstance, matName);
|
|
|
|
for (var i = 0; i < mats.length; i++) {
|
|
var mat = mats[i];
|
|
|
|
if (mat.isMeshNodeMaterial) {
|
|
var rgbIdx = mat.nodeRGBMap[colName];
|
|
mat.nodeRGB[rgbIdx].x = r;
|
|
mat.nodeRGB[rgbIdx].y = g;
|
|
mat.nodeRGB[rgbIdx].z = b;
|
|
} else {
|
|
mat[colName].r = r;
|
|
mat[colName].g = g;
|
|
mat[colName].b = b;
|
|
}
|
|
mat.needsUpdate = true;
|
|
|
|
if (mat === appInstance.worldMaterial)
|
|
appInstance.updateEnvironment(mat);
|
|
}
|
|
}
|
|
|
|
|
|
function setRGB(r, g, b) {
|
|
setMaterialColor("transparent", "Principled BSDF Color", r, g, b);
|
|
}
|
|
appInstance.ExternalInterface["setRGB"] = setRGB;
|
|
|
|
|
|
|
|
// bloom puzzle
|
|
function bloom(threshold, strength, radius) {
|
|
appInstance.enablePostprocessing([{
|
|
type: 'bloom',
|
|
threshold: threshold,
|
|
strength: strength,
|
|
radius: radius
|
|
}]);
|
|
}
|
|
|
|
|
|
|
|
// ssao puzzle
|
|
function ssao(radius, aoClamp, lumInfluence) {
|
|
appInstance.enablePostprocessing([{
|
|
type: 'ssao',
|
|
radius: radius,
|
|
aoClamp: aoClamp,
|
|
lumInfluence: lumInfluence
|
|
}]);
|
|
}
|
|
|
|
|
|
|
|
// getEventProperty puzzle
|
|
function getEventProperty(prop, event) {
|
|
if (typeof event != "undefined") {
|
|
if (prop == "target.id")
|
|
return event.target.id;
|
|
else
|
|
return event[prop];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// utility functions envoked by the HTML puzzles
|
|
function getElements(ids, isParent) {
|
|
var elems = [];
|
|
if (Array.isArray(ids) && ids[0] != "WINDOW" && ids[0] != "DOCUMENT" && ids[0] != "BODY") {
|
|
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] == "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 (isParent)
|
|
elem = parent.document.getElementById(id);
|
|
else
|
|
elem = document.getElementById(id);
|
|
}
|
|
return elem;
|
|
}
|
|
|
|
|
|
|
|
// eventHTMLElem puzzle
|
|
function eventHTMLElem(eventType, ids, isParent, callback) {
|
|
var elems = getElements(ids, isParent);
|
|
for (var i = 0; i < elems.length; i++) {
|
|
var elem = elems[i];
|
|
if (!elem)
|
|
continue;
|
|
elem.addEventListener(eventType, callback, false);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
distZ = getObjTransform("qubit", "position", "y") - getObjTransform("qubit_controller", "position", "y");
|
|
distY = getObjTransform("qubit", "position", "z") - getObjTransform("qubit_controller", "position", "z");
|
|
distX = getObjTransform("qubit", "position", "x") - getObjTransform("qubit_controller", "position", "x");
|
|
maxDist = 2;
|
|
stepY = 0.1;
|
|
|
|
registerOnClick("bit", function() {
|
|
if (getObjectMaterial("bit") == "white") {
|
|
assignMat("bit", "black");
|
|
} else {
|
|
assignMat("bit", "white");
|
|
}
|
|
}, function() {});
|
|
|
|
registerOnDrag(["GROUP", "qubit_grp"], function() {
|
|
dragging = true;
|
|
},
|
|
function() {
|
|
dragMove("qubit_controller", "XY", "5{hamS]l^diNZ_?={UNM", "x7;j`9Tr6$fIW]tXfLwm");
|
|
inboundStepper = 0;
|
|
distZ = getObjTransform("qubit", "position", "y") - getObjTransform("qubit_controller", "position", "y");
|
|
distX = getObjTransform("qubit", "position", "x") - getObjTransform("qubit_controller", "position", "x");
|
|
while (getDistanceBetweenObjects("qubit_controller", "qubit") > maxDist) {
|
|
inboundStepper = (typeof inboundStepper == 'number' ? inboundStepper : 0) + 1;
|
|
applyObjLocalTransform("qubit_controller", "position", (distX / 50) * inboundStepper, 0, (distZ / 50) * inboundStepper);
|
|
}
|
|
hue = 0;
|
|
sat = Math.sqrt(distX * distX + distY * distY) / maxDist;
|
|
value = ((distZ - maxDist) / (2 * maxDist)) * -1;
|
|
getJSFunction('HSVtoRGB')(hue, sat, value);
|
|
},
|
|
function() {
|
|
dragging = false;
|
|
}, "x7;j`9Tr6$fIW]tXfLwm");
|
|
|
|
bloom(0.5, 0.2, 0.15);
|
|
ssao(2, 0.25, 0.7);
|
|
|
|
eventHTMLElem('wheel', ["DOCUMENT"], false, function(event) {
|
|
if (dragging == true) {
|
|
if (getEventProperty('deltaY', event) < 0) {
|
|
applyObjLocalTransform("qubit_controller", "position", 0, stepY, 0);
|
|
if (getDistanceBetweenObjects("qubit_controller", "qubit") >= maxDist) {
|
|
applyObjLocalTransform("qubit_controller", "position", 0, stepY * -1, 0);
|
|
}
|
|
} else if (getEventProperty('deltaY', event) > 0) {
|
|
applyObjLocalTransform("qubit_controller", "position", 0, stepY * -1, 0);
|
|
if (getDistanceBetweenObjects("qubit_controller", "qubit") >= maxDist) {
|
|
applyObjLocalTransform("qubit_controller", "position", 0, stepY, 0);
|
|
}
|
|
}
|
|
distY = getObjTransform("qubit", "position", "z") - getObjTransform("qubit_controller", "position", "z");
|
|
sat = Math.sqrt(distX * distX + distY * distY) / maxDist;
|
|
}
|
|
});
|
|
|
|
stepY;
|
|
|
|
} // end of PL.init function
|
|
|
|
if (window.v3dApp) {
|
|
// backwards compatibility for old player projects
|
|
PL.legacyMode = true;
|
|
PL.init(window.v3dApp);
|
|
}
|
|
|
|
})(); // end of closure
|
|
|
|
/* ================================ end of code ============================= */
|