396 lines · 9.9 KB · JavaScript
RawDownload
////  inspect.js//  examples////  Created by Clément Brisset on March 20, 2014//  Copyright 2014 High Fidelity, Inc.////  Enables you to inspect entities and avatars using Alt and key combinations://  - Alt + mouse up/down zooms in/out.//  - Alt + mouse left/right orbits left/right.//  - Alt + Ctrl + mouse up/down/left/right: orbits over / under / left / right.//  - Alt + Ctrl + Shift + mouse up/down/left/right: pans down / up / right / left.////  Your camera stays where it is when you release the Alt key, enabling you to Alt + left - click on another entity or //  avatar to further move your view.////  Press Esc or move your avatar to revert back to your default view.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// var PI = Math.PI;var RAD_TO_DEG = 180.0 / PI; var AZIMUTH_RATE = 90.0;var ALTITUDE_RATE = 200.0;var RADIUS_RATE = 1.0 / 100.0;var PAN_RATE = 250.0; var AVATAR_POSITION_SLOP = 0.1;var AVATAR_ROTATION_SLOP = 0.09; // 5 degrees var Y_AXIS = {    x: 0,    y: 1,    z: 0};var X_AXIS = {    x: 1,    y: 0,    z: 0}; var LOOK_AT_TIME = 100; // ms var alt = false;var shift = false;var control = false; var isActive = false; var oldMode = Camera.mode;var noMode = 0;var orbitMode = 1;var radialMode = 2;var panningMode = 3;var detachedMode = 4; var mode = noMode; var isAwayEnabled = true; var EDIT_CAMERA_MANAGER_CHANNEL = "Edit-Camera-Manager-Channel";var isEditUsingCamera = false;Messages.messageReceived.connect(function (channel, data, senderID, localOnly) {    if (channel === EDIT_CAMERA_MANAGER_CHANNEL && senderID === MyAvatar.sessionUUID && localOnly) {        var message;        try {            message = JSON.parse(data);            isEditUsingCamera = message.enabled;        } catch (e) {            // Ignore.        }    }}); var pick = Picks.createPick(PickType.Ray, {    filter: Picks.PICK_DOMAIN_ENTITIES | Picks.PICK_AVATAR_ENTITIES | Picks.PICK_AVATARS | Picks.INCLUDE_VISIBLE        | Picks.PICK_INCLUDE_COLLIDABLE | Picks.PICK_INCLUDE_NONCOLLIDABLE | Picks.PICK_PRECISE,    joint: "Mouse",    enabled: false}); var mouseLastX = 0;var mouseLastY = 0; var center = {    x: 0,    y: 0,    z: 0};var position = {    x: 0,    y: 0,    z: 0};var vector = {    x: 0,    y: 0,    z: 0};var radius = 0.0;var azimuth = 0.0;var altitude = 0.0; var avatarPosition;var avatarOrientation; var rotatingTowardsTarget = false;var targetCamOrientation;var oldPosition, oldOrientation; function orientationOf(vector) {    var direction,        yaw,        pitch;     direction = Vec3.normalize(vector);    yaw = Quat.angleAxis(Math.atan2(direction.x, direction.z) * RAD_TO_DEG, Y_AXIS);    pitch = Quat.angleAxis(Math.asin(-direction.y) * RAD_TO_DEG, X_AXIS);    return Quat.multiply(yaw, pitch);} function handleRadialMode(dx, dy) {    var MIN_INSPECT_RADIUS = 0.1;    azimuth += dx / AZIMUTH_RATE;    radius += radius * dy * RADIUS_RATE;    if (radius < MIN_INSPECT_RADIUS) {        radius = MIN_INSPECT_RADIUS;    }     vector = {        x: (Math.cos(altitude) * Math.cos(azimuth)) * radius,        y: Math.sin(altitude) * radius,        z: (Math.cos(altitude) * Math.sin(azimuth)) * radius    };    position = Vec3.sum(center, vector);    Camera.setPosition(position);    Camera.setOrientation(orientationOf(vector));} function handleOrbitMode(dx, dy) {    azimuth += dx / AZIMUTH_RATE;    altitude += dy / ALTITUDE_RATE;    if (altitude > PI / 2.0) {        altitude = PI / 2.0;    }    if (altitude < -PI / 2.0) {        altitude = -PI / 2.0;    }     vector = {        x: (Math.cos(altitude) * Math.cos(azimuth)) * radius,        y: Math.sin(altitude) * radius,        z: (Math.cos(altitude) * Math.sin(azimuth)) * radius    };    position = Vec3.sum(center, vector);    Camera.setPosition(position);    Camera.setOrientation(orientationOf(vector));} function handlePanMode(dx, dy) {    var up = Quat.getUp(Camera.getOrientation());    var right = Quat.getRight(Camera.getOrientation());    var distance = Vec3.length(vector);     var dv = Vec3.sum(Vec3.multiply(up, distance * dy / PAN_RATE), Vec3.multiply(right, -distance * dx / PAN_RATE));     center = Vec3.sum(center, dv);    position = Vec3.sum(position, dv);     Camera.setPosition(position);    Camera.setOrientation(orientationOf(vector));} function enableAway(enable) {    if (enable !== isAwayEnabled) {        var CHANNEL_AWAY_ENABLE = "Hifi-Away-Enable";        Messages.sendMessage(CHANNEL_AWAY_ENABLE, enable ? "enable" : "disable", true);    }    isAwayEnabled = enable;} function saveCameraState() {    oldMode = Camera.mode;    oldPosition = Camera.getPosition();    oldOrientation = Camera.getOrientation();     Camera.mode = "independent";    Camera.setPosition(oldPosition);} function restoreCameraState() {    Camera.mode = oldMode;    Camera.setPosition(oldPosition);    Camera.setOrientation(oldOrientation);} function handleModes() {    if (isEditUsingCamera) {        return;    }     var newMode = (mode === noMode) ? noMode : detachedMode;    if (alt) {        if (control) {            if (shift) {                newMode = panningMode;            } else {                newMode = orbitMode;            }        } else {            newMode = radialMode;        }    }     // if entering detachMode    if (newMode === detachedMode && mode !== detachedMode) {        avatarPosition = MyAvatar.position;        avatarOrientation = MyAvatar.orientation;    }    // if leaving detachMode    if (mode === detachedMode && newMode === detachedMode && (        Vec3.length(Vec3.subtract(avatarPosition, MyAvatar.position)) > AVATAR_POSITION_SLOP        || Vec3.length(Vec3.subtract(Quat.getFront(avatarOrientation), Quat.getFront(MyAvatar.orientation)))            > AVATAR_ROTATION_SLOP)) {        newMode = noMode;    }     if (mode === noMode && newMode !== noMode && Camera.mode === "independent") {        newMode = noMode;    }     // if leaving noMode    if (mode === noMode && newMode !== noMode) {        saveCameraState();    }    // if entering noMode    if (newMode === noMode && mode !== noMode) {        restoreCameraState();    }     mode = newMode;     enableAway(mode === noMode);} function keyPressEvent(event) {    var changed = false;     if (event.text === "ALT") {        if (isEditUsingCamera) {            return;        }        if (Settings.getValue("mouselook-active", false)){            return;        }        alt = true;        changed = true;        Picks.enablePick(pick);    }    if (event.text === "CONTROL") {        control = true;        changed = true;    }    if (event.text === "SHIFT") {        shift = true;        changed = true;    }     if (mode !== noMode && !alt && !control && !shift && /^ESC|LEFT|RIGHT|UP|DOWN|[wasdWASD]$/.test(event.text)) {        mode = noMode;        restoreCameraState();        changed = true;    }     if (changed) {        handleModes();    }} function keyReleaseEvent(event) {    var changed = false;     if (event.text === "ALT") {        alt = false;        changed = true;        Picks.disablePick(pick);    }    if (event.text === "CONTROL") {        control = false;        changed = true;    }    if (event.text === "SHIFT") {        shift = false;        changed = true;    }     if (changed) {        handleModes();    }} function mousePressEvent(event) {    if (alt && !isActive) {        mouseLastX = event.x;        mouseLastY = event.y;         position = Camera.position;         var pickResult = Picks.getPrevPickResult(pick);        if (pickResult.intersects) {            // Orbit about intersection.            center = pickResult.intersection;        } else {            // Orbit about point in space.            var ORBIT_DISTANCE = 10.0;            center = Vec3.sum(position, Vec3.multiply(ORBIT_DISTANCE, pickResult.searchRay.direction));        }         // We've selected our target, now orbit towards it automatically        rotatingTowardsTarget = true;        // calculate our target cam rotation        Script.setTimeout(function () {            rotatingTowardsTarget = false;        }, LOOK_AT_TIME);         vector = Vec3.subtract(position, center);        targetCamOrientation = orientationOf(vector);        radius = Vec3.length(vector);        azimuth = Math.atan2(vector.z, vector.x);        altitude = Math.asin(vector.y / Vec3.length(vector));         isActive = true;    }} function mouseReleaseEvent(event) {    if (isActive) {        isActive = false;    }} function mouseMoveEvent(event) {    if (isActive && mode !== noMode && !rotatingTowardsTarget) {        if (mode === radialMode) {            handleRadialMode(event.x - mouseLastX, event.y - mouseLastY);        }        if (mode === orbitMode) {            handleOrbitMode(event.x - mouseLastX, event.y - mouseLastY);        }        if (mode === panningMode) {            handlePanMode(event.x - mouseLastX, event.y - mouseLastY);        }    }    mouseLastX = event.x;    mouseLastY = event.y;} function onCameraModeUpdated(newMode) {    mode = noMode;    handleModes();} function update() {    handleModes();    if (rotatingTowardsTarget) {        rotateTowardsTarget();    }} function rotateTowardsTarget() {    var MIX_FACTOR = 0.1;    var newOrientation = Quat.mix(Camera.getOrientation(), targetCamOrientation, MIX_FACTOR);    Camera.setOrientation(newOrientation);} function scriptEnding() {    if (mode !== noMode) {        restoreCameraState();        enableAway(true);    }} Controller.keyPressEvent.connect(keyPressEvent);Controller.keyReleaseEvent.connect(keyReleaseEvent); Controller.mousePressEvent.connect(mousePressEvent);Controller.mouseReleaseEvent.connect(mouseReleaseEvent);Controller.mouseMoveEvent.connect(mouseMoveEvent); Camera.modeUpdated.connect(onCameraModeUpdated); Script.update.connect(update);Script.scriptEnding.connect(scriptEnding);