mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 04:44:11 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into attenuation_zones
Conflicts: domain-server/resources/web/js/settings.js
This commit is contained in:
commit
fb751aec7c
25 changed files with 1481 additions and 158 deletions
|
@ -156,7 +156,6 @@ $(document).ready(function(){
|
|||
})
|
||||
|
||||
$('#settings-form').on('change', 'select', function(){
|
||||
console.log("Changed" + $(this))
|
||||
$("input[name='" + $(this).attr('data-hidden-input') + "']").val($(this).val()).change()
|
||||
})
|
||||
|
||||
|
@ -492,7 +491,7 @@ function deleteTableRow(delete_glyphicon) {
|
|||
|
||||
row.removeClass(Settings.DATA_ROW_CLASS).removeClass(Settings.NEW_ROW_CLASS)
|
||||
row.addClass('empty-array-row')
|
||||
|
||||
|
||||
row.html("<input type='hidden' class='form-control' name='" + table.attr("name").replace('[]', '')
|
||||
+ "' data-changed='true' value=''>");
|
||||
}
|
||||
|
|
280
examples/gamepad.js
Normal file
280
examples/gamepad.js
Normal file
|
@ -0,0 +1,280 @@
|
|||
//
|
||||
// controller.js
|
||||
// examples
|
||||
//
|
||||
// Created by Ryan Huffman on 10/9/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// TODO Update to work with any controller that is plugged in.
|
||||
var CONTROLLER_NAMES = [
|
||||
"Wireless 360 Controller",
|
||||
"Controller (XBOX 360 For Windows)",
|
||||
"Controller", // Wired 360 controller
|
||||
]
|
||||
|
||||
for (var i = 0; i < CONTROLLER_NAMES.length; i++) {
|
||||
gamepad = Joysticks.joystickWithName(CONTROLLER_NAMES[i]);
|
||||
if (gamepad) {
|
||||
print("Found controller: " + CONTROLLER_NAMES[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!gamepad) {
|
||||
print("No gamepad found.");
|
||||
}
|
||||
|
||||
// Controller axis/button mappings
|
||||
var GAMEPAD = {
|
||||
AXES: {
|
||||
LEFT_JOYSTICK_X: 0,
|
||||
LEFT_JOYSTICK_Y: 1,
|
||||
|
||||
RIGHT_JOYSTICK_X: 2,
|
||||
RIGHT_JOYSTICK_Y: 3,
|
||||
|
||||
LEFT_TRIGGER: 4,
|
||||
RIGHT_TRIGGER: 5,
|
||||
},
|
||||
BUTTONS: {
|
||||
DPAD_UP: 0,
|
||||
DPAD_DOWN: 1,
|
||||
DPAD_LEFT: 2,
|
||||
DPAD_RIGHT: 3,
|
||||
|
||||
LEFT_JOYSTICK: 6,
|
||||
RIGHT_JOYSTICK: 7,
|
||||
|
||||
LEFT_BUMPER: 8,
|
||||
RIGHT_BUMPER: 9,
|
||||
|
||||
// Face buttons, ABXY on an XBOX controller
|
||||
FACE_BOTTOM: 11,
|
||||
FACE_RIGHT: 12,
|
||||
FACE_LEFT: 13,
|
||||
FACE_TOP: 14,
|
||||
}
|
||||
}
|
||||
|
||||
// Button/axis mappings
|
||||
var AXIS_STRAFE = GAMEPAD.AXES.LEFT_JOYSTICK_X;
|
||||
var AXIS_FORWARD = GAMEPAD.AXES.LEFT_JOYSTICK_Y;
|
||||
var AXIS_ROTATE = GAMEPAD.AXES.RIGHT_JOYSTICK_X;
|
||||
|
||||
var BUTTON_TURN_AROUND = GAMEPAD.BUTTONS.RIGHT_JOYSTICK;
|
||||
|
||||
var BUTTON_FLY_UP = GAMEPAD.BUTTONS.RIGHT_BUMPER;
|
||||
var BUTTON_FLY_DOWN = GAMEPAD.BUTTONS.LEFT_BUMPER
|
||||
var BUTTON_WARP = GAMEPAD.BUTTONS.FACE_BOTTOM;
|
||||
|
||||
var BUTTON_WARP_FORWARD = GAMEPAD.BUTTONS.DPAD_UP;
|
||||
var BUTTON_WARP_BACKWARD = GAMEPAD.BUTTONS.DPAD_DOWN;
|
||||
var BUTTON_WARP_LEFT = GAMEPAD.BUTTONS.DPAD_LEFT;
|
||||
var BUTTON_WARP_RIGHT = GAMEPAD.BUTTONS.DPAD_RIGHT;
|
||||
|
||||
// Distance in meters to warp via BUTTON_WARP_*
|
||||
var WARP_DISTANCE = 1;
|
||||
|
||||
// Walk speed in m/s
|
||||
var MOVE_SPEED = 2;
|
||||
|
||||
// Amount to rotate in radians
|
||||
var ROTATE_INCREMENT = Math.PI / 8;
|
||||
|
||||
// Pick from above where we want to warp
|
||||
var WARP_PICK_OFFSET = { x: 0, y: 10, z: 0 };
|
||||
|
||||
// When warping, the warp position will snap to a target below the current warp position.
|
||||
// This is the max distance it will snap to.
|
||||
var WARP_PICK_MAX_DISTANCE = 100;
|
||||
|
||||
var flyDownButtonState = false;
|
||||
var flyUpButtonState = false;
|
||||
|
||||
// Current move direction, axis aligned - that is, looking down and moving forward
|
||||
// will not move you into the ground, but instead will keep you on the horizontal plane.
|
||||
var moveDirection = { x: 0, y: 0, z: 0 };
|
||||
|
||||
var warpActive = false;
|
||||
var warpPosition = { x: 0, y: 0, z: 0 };
|
||||
|
||||
var WARP_SPHERE_SIZE = 1;
|
||||
var warpSphere = Overlays.addOverlay("sphere", {
|
||||
position: { x: 0, y: 0, z: 0 },
|
||||
size: WARP_SPHERE_SIZE,
|
||||
color: { red: 0, green: 255, blue: 0 },
|
||||
alpha: 1.0,
|
||||
solid: true,
|
||||
visible: false,
|
||||
});
|
||||
|
||||
var WARP_LINE_HEIGHT = 10;
|
||||
var warpLine = Overlays.addOverlay("line3d", {
|
||||
position: { x: 0, y: 0, z:0 },
|
||||
end: { x: 0, y: 0, z: 0 },
|
||||
color: { red: 0, green: 255, blue: 255},
|
||||
alpha: 1,
|
||||
lineWidth: 5,
|
||||
visible: false,
|
||||
});
|
||||
|
||||
function copyVec3(vec) {
|
||||
return { x: vec.x, y: vec.y, z: vec.z };
|
||||
}
|
||||
|
||||
function activateWarp() {
|
||||
if (warpActive) return;
|
||||
warpActive = true;
|
||||
|
||||
updateWarp();
|
||||
}
|
||||
|
||||
function updateWarp() {
|
||||
if (!warpActive) return;
|
||||
|
||||
var look = Quat.getFront(Camera.getOrientation());
|
||||
var pitch = Math.asin(look.y);
|
||||
|
||||
// Get relative to looking straight down
|
||||
pitch += Math.PI / 2;
|
||||
|
||||
// Scale up
|
||||
pitch *= 2;
|
||||
var distance = pitch * pitch * pitch;
|
||||
|
||||
var warpDirection = Vec3.normalize({ x: look.x, y: 0, z: look.z });
|
||||
warpPosition = Vec3.multiply(warpDirection, distance);
|
||||
warpPosition = Vec3.sum(MyAvatar.position, warpPosition);
|
||||
|
||||
var pickRay = {
|
||||
origin: Vec3.sum(warpPosition, WARP_PICK_OFFSET),
|
||||
direction: { x: 0, y: -1, z: 0 }
|
||||
};
|
||||
|
||||
var intersection = Voxels.findRayIntersection(pickRay);
|
||||
|
||||
if (intersection.intersects && intersection.distance < WARP_PICK_MAX_DISTANCE) {
|
||||
// Warp 1 meter above the object - this is an approximation
|
||||
// TODO Get the actual offset to the Avatar's feet and plant them to
|
||||
// the object.
|
||||
warpPosition = Vec3.sum(intersection.intersection, { x: 0, y: 1, z:0 });
|
||||
}
|
||||
|
||||
// Adjust overlays to match warp position
|
||||
Overlays.editOverlay(warpSphere, {
|
||||
position: warpPosition,
|
||||
visible: true,
|
||||
});
|
||||
Overlays.editOverlay(warpLine, {
|
||||
position: warpPosition,
|
||||
end: Vec3.sum(warpPosition, { x: 0, y: WARP_LINE_HEIGHT, z: 0 }),
|
||||
visible: true,
|
||||
});
|
||||
}
|
||||
|
||||
function finishWarp() {
|
||||
if (!warpActive) return;
|
||||
warpActive = false;
|
||||
Overlays.editOverlay(warpSphere, {
|
||||
visible: false,
|
||||
});
|
||||
Overlays.editOverlay(warpLine, {
|
||||
visible: false,
|
||||
});
|
||||
MyAvatar.position = warpPosition;
|
||||
}
|
||||
|
||||
function reportAxisValue(axis, newValue, oldValue) {
|
||||
if (Math.abs(oldValue) < 0.2) oldValue = 0;
|
||||
if (Math.abs(newValue) < 0.2) newValue = 0;
|
||||
|
||||
if (axis == AXIS_FORWARD) {
|
||||
moveDirection.z = newValue;
|
||||
} else if (axis == AXIS_STRAFE) {
|
||||
moveDirection.x = newValue;
|
||||
} else if (axis == AXIS_ROTATE) {
|
||||
if (oldValue == 0 && newValue != 0) {
|
||||
var rotateRadians = newValue > 0 ? -ROTATE_INCREMENT : ROTATE_INCREMENT;
|
||||
var orientation = MyAvatar.orientation;
|
||||
orientation = Quat.multiply(Quat.fromPitchYawRollRadians(0, rotateRadians, 0), orientation) ;
|
||||
MyAvatar.orientation = orientation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function reportButtonValue(button, newValue, oldValue) {
|
||||
if (button == BUTTON_FLY_DOWN) {
|
||||
flyDownButtonState = newValue;
|
||||
} else if (button == BUTTON_FLY_UP) {
|
||||
flyUpButtonState = newValue;
|
||||
} else if (button == BUTTON_WARP) {
|
||||
if (newValue) {
|
||||
activateWarp();
|
||||
} else {
|
||||
finishWarp();
|
||||
}
|
||||
} else if (button == BUTTON_TURN_AROUND) {
|
||||
if (newValue) {
|
||||
MyAvatar.orientation = Quat.multiply(
|
||||
Quat.fromPitchYawRollRadians(0, Math.PI, 0), MyAvatar.orientation);
|
||||
}
|
||||
} else if (newValue) {
|
||||
var direction = null;
|
||||
|
||||
if (button == BUTTON_WARP_FORWARD) {
|
||||
direction = Quat.getFront(Camera.getOrientation());
|
||||
} else if (button == BUTTON_WARP_BACKWARD) {
|
||||
direction = Quat.getFront(Camera.getOrientation());
|
||||
direction = Vec3.multiply(-1, direction);
|
||||
} else if (button == BUTTON_WARP_LEFT) {
|
||||
direction = Quat.getRight(Camera.getOrientation());
|
||||
direction = Vec3.multiply(-1, direction);
|
||||
} else if (button == BUTTON_WARP_RIGHT) {
|
||||
direction = Quat.getRight(Camera.getOrientation());
|
||||
}
|
||||
|
||||
if (direction) {
|
||||
direction.y = 0;
|
||||
direction = Vec3.multiply(Vec3.normalize(direction), WARP_DISTANCE);
|
||||
MyAvatar.position = Vec3.sum(MyAvatar.position, direction);
|
||||
}
|
||||
}
|
||||
|
||||
if (flyUpButtonState && !flyDownButtonState) {
|
||||
moveDirection.y = 1;
|
||||
} else if (!flyUpButtonState && flyDownButtonState) {
|
||||
moveDirection.y = -1;
|
||||
} else {
|
||||
moveDirection.y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function update(dt) {
|
||||
var velocity = { x: 0, y: 0, z: 0 };
|
||||
var move = copyVec3(moveDirection);
|
||||
move.y = 0;
|
||||
if (Vec3.length(move) > 0) {
|
||||
velocity = Vec3.multiplyQbyV(Camera.getOrientation(), move);
|
||||
velocity.y = 0;
|
||||
velocity = Vec3.multiply(Vec3.normalize(velocity), MOVE_SPEED);
|
||||
}
|
||||
|
||||
if (moveDirection.y != 0) {
|
||||
velocity.y = moveDirection.y * MOVE_SPEED;
|
||||
}
|
||||
|
||||
MyAvatar.setVelocity(velocity);
|
||||
|
||||
updateWarp();
|
||||
}
|
||||
|
||||
if (gamepad) {
|
||||
gamepad.axisValueChanged.connect(reportAxisValue);
|
||||
gamepad.buttonStateChanged.connect(reportButtonValue);
|
||||
|
||||
Script.update.connect(update);
|
||||
}
|
|
@ -244,7 +244,7 @@ EntityPropertyDialogBox = (function () {
|
|||
properties.color.blue = array[index++].value;
|
||||
}
|
||||
Entities.editEntity(editModelID, properties);
|
||||
selectionDisplay.highlightSelectable(editModelID, propeties);
|
||||
selectionDisplay.select(editModelID, false);
|
||||
}
|
||||
modelSelected = false;
|
||||
});
|
||||
|
|
|
@ -31,10 +31,33 @@ SelectionDisplay = (function () {
|
|||
var handleHoverColor = { red: 224, green: 67, blue: 36 };
|
||||
var handleHoverAlpha = 1.0;
|
||||
|
||||
var rotateOverlayTargetSize = 10000; // really big target
|
||||
var innerSnapAngle = 22.5; // the angle which we snap to on the inner rotation tool
|
||||
var innerRadius;
|
||||
var outerRadius;
|
||||
var yawHandleRotation;
|
||||
var pitchHandleRotation;
|
||||
var rollHandleRotation;
|
||||
var yawCenter;
|
||||
var pitchCenter;
|
||||
var rollCenter;
|
||||
var yawZero;
|
||||
var pitchZero;
|
||||
var rollZero;
|
||||
var yawNormal;
|
||||
var pitchNormal;
|
||||
var rollNormal;
|
||||
var rotationNormal;
|
||||
|
||||
var originalRotation;
|
||||
var originalPitch;
|
||||
var originalYaw;
|
||||
var originalRoll;
|
||||
|
||||
|
||||
var rotateHandleColor = { red: 0, green: 0, blue: 0 };
|
||||
var rotateHandleAlpha = 0.7;
|
||||
|
||||
|
||||
var grabberSizeCorner = 0.025;
|
||||
var grabberSizeEdge = 0.015;
|
||||
var grabberSizeFace = 0.025;
|
||||
|
@ -151,7 +174,8 @@ SelectionDisplay = (function () {
|
|||
alpha: 0.5,
|
||||
solid: true,
|
||||
visible: false,
|
||||
rotation: baseOverlayRotation
|
||||
rotation: baseOverlayRotation,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
});
|
||||
|
||||
var yawOverlayAngles = { x: 90, y: 0, z: 0 };
|
||||
|
@ -161,6 +185,34 @@ SelectionDisplay = (function () {
|
|||
var rollOverlayAngles = { x: 0, y: 180, z: 0 };
|
||||
var rollOverlayRotation = Quat.fromVec3Degrees(rollOverlayAngles);
|
||||
|
||||
var rotateZeroOverlay = Overlays.addOverlay("line3d", {
|
||||
visible: false,
|
||||
lineWidth: 2.0,
|
||||
start: { x: 0, y: 0, z: 0 },
|
||||
end: { x: 0, y: 0, z: 0 },
|
||||
color: { red: 255, green: 0, blue: 0 },
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
});
|
||||
|
||||
var rotateCurrentOverlay = Overlays.addOverlay("line3d", {
|
||||
visible: false,
|
||||
lineWidth: 2.0,
|
||||
start: { x: 0, y: 0, z: 0 },
|
||||
end: { x: 0, y: 0, z: 0 },
|
||||
color: { red: 0, green: 0, blue: 255 },
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
});
|
||||
|
||||
|
||||
var rotateOverlayTarget = Overlays.addOverlay("circle3d", {
|
||||
position: { x:0, y: 0, z: 0},
|
||||
size: rotateOverlayTargetSize,
|
||||
color: { red: 0, green: 0, blue: 0 },
|
||||
alpha: 0.0,
|
||||
solid: true,
|
||||
visible: false,
|
||||
rotation: yawOverlayRotation,
|
||||
});
|
||||
|
||||
var rotateOverlayInner = Overlays.addOverlay("circle3d", {
|
||||
position: { x:0, y: 0, z: 0},
|
||||
|
@ -171,12 +223,13 @@ SelectionDisplay = (function () {
|
|||
visible: false,
|
||||
rotation: yawOverlayRotation,
|
||||
hasTickMarks: true,
|
||||
majorTickMarksAngle: 12.5,
|
||||
majorTickMarksAngle: innerSnapAngle,
|
||||
minorTickMarksAngle: 0,
|
||||
majorTickMarksLength: -0.25,
|
||||
minorTickMarksLength: 0,
|
||||
majorTickMarksColor: { red: 0, green: 0, blue: 0 },
|
||||
minorTickMarksColor: { red: 0, green: 0, blue: 0 },
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
});
|
||||
|
||||
var rotateOverlayOuter = Overlays.addOverlay("circle3d", {
|
||||
|
@ -195,6 +248,7 @@ SelectionDisplay = (function () {
|
|||
minorTickMarksLength: 0.1,
|
||||
majorTickMarksColor: { red: 0, green: 0, blue: 0 },
|
||||
minorTickMarksColor: { red: 0, green: 0, blue: 0 },
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
});
|
||||
|
||||
var rotateOverlayCurrent = Overlays.addOverlay("circle3d", {
|
||||
|
@ -205,10 +259,11 @@ SelectionDisplay = (function () {
|
|||
solid: true,
|
||||
visible: false,
|
||||
rotation: yawOverlayRotation,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
});
|
||||
|
||||
var yawHandle = Overlays.addOverlay("billboard", {
|
||||
url: "https://s3.amazonaws.com/uploads.hipchat.com/33953/231323/HRRhkMk8ueLk8ku/rotate-arrow.png",
|
||||
url: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/rotate-arrow-west-north.png",
|
||||
position: { x:0, y: 0, z: 0},
|
||||
color: rotateHandleColor,
|
||||
alpha: rotateHandleAlpha,
|
||||
|
@ -220,7 +275,7 @@ SelectionDisplay = (function () {
|
|||
|
||||
|
||||
var pitchHandle = Overlays.addOverlay("billboard", {
|
||||
url: "https://s3.amazonaws.com/uploads.hipchat.com/33953/231323/HRRhkMk8ueLk8ku/rotate-arrow.png",
|
||||
url: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/rotate-arrow-west-north.png",
|
||||
position: { x:0, y: 0, z: 0},
|
||||
color: rotateHandleColor,
|
||||
alpha: rotateHandleAlpha,
|
||||
|
@ -232,7 +287,7 @@ SelectionDisplay = (function () {
|
|||
|
||||
|
||||
var rollHandle = Overlays.addOverlay("billboard", {
|
||||
url: "https://s3.amazonaws.com/uploads.hipchat.com/33953/231323/HRRhkMk8ueLk8ku/rotate-arrow.png",
|
||||
url: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/rotate-arrow-west-north.png",
|
||||
position: { x:0, y: 0, z: 0},
|
||||
color: rotateHandleColor,
|
||||
alpha: rotateHandleAlpha,
|
||||
|
@ -279,11 +334,14 @@ SelectionDisplay = (function () {
|
|||
overlayNames[pitchHandle] = "pitchHandle";
|
||||
overlayNames[rollHandle] = "rollHandle";
|
||||
|
||||
overlayNames[rotateOverlayTarget] = "rotateOverlayTarget";
|
||||
overlayNames[rotateOverlayInner] = "rotateOverlayInner";
|
||||
overlayNames[rotateOverlayOuter] = "rotateOverlayOuter";
|
||||
overlayNames[rotateOverlayCurrent] = "rotateOverlayCurrent";
|
||||
|
||||
|
||||
overlayNames[rotateZeroOverlay] = "rotateZeroOverlay";
|
||||
overlayNames[rotateCurrentOverlay] = "rotateCurrentOverlay";
|
||||
|
||||
that.cleanup = function () {
|
||||
Overlays.deleteOverlay(highlightBox);
|
||||
Overlays.deleteOverlay(selectionBox);
|
||||
|
@ -322,10 +380,15 @@ SelectionDisplay = (function () {
|
|||
Overlays.deleteOverlay(pitchHandle);
|
||||
Overlays.deleteOverlay(rollHandle);
|
||||
|
||||
Overlays.deleteOverlay(rotateOverlayTarget);
|
||||
Overlays.deleteOverlay(rotateOverlayInner);
|
||||
Overlays.deleteOverlay(rotateOverlayOuter);
|
||||
Overlays.deleteOverlay(rotateOverlayCurrent);
|
||||
|
||||
Overlays.deleteOverlay(rotateZeroOverlay);
|
||||
Overlays.deleteOverlay(rotateCurrentOverlay);
|
||||
|
||||
|
||||
};
|
||||
|
||||
that.highlightSelectable = function(entityID) {
|
||||
|
@ -377,8 +440,8 @@ SelectionDisplay = (function () {
|
|||
|
||||
var diagonal = (Vec3.length(properties.dimensions) / 2) * 1.1;
|
||||
var halfDimensions = Vec3.multiply(properties.dimensions, 0.5);
|
||||
var innerRadius = diagonal;
|
||||
var outerRadius = diagonal * 1.15;
|
||||
innerRadius = diagonal;
|
||||
outerRadius = diagonal * 1.15;
|
||||
var innerActive = false;
|
||||
var innerAlpha = 0.2;
|
||||
var outerAlpha = 0.2;
|
||||
|
@ -412,10 +475,6 @@ SelectionDisplay = (function () {
|
|||
var pitchCorner;
|
||||
var rollCorner;
|
||||
|
||||
var yawHandleRotation;
|
||||
var pitchHandleRotation;
|
||||
var rollHandleRotation;
|
||||
|
||||
// determine which bottom corner we are closest to
|
||||
/*------------------------------
|
||||
example:
|
||||
|
@ -432,27 +491,45 @@ SelectionDisplay = (function () {
|
|||
if (MyAvatar.position.x > center.x) {
|
||||
// must be BRF or BRN
|
||||
if (MyAvatar.position.z < center.z) {
|
||||
yawHandleRotation = Quat.fromVec3Degrees({ x: 90, y: 0, z: 0 });
|
||||
pitchHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 180, z: 180 });
|
||||
rollHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 90, z: 180 });
|
||||
yawHandleRotation = Quat.fromVec3Degrees({ x: 270, y: 90, z: 0 });
|
||||
pitchHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 90, z: 0 });
|
||||
rollHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 0 });
|
||||
|
||||
yawNormal = { x: 0, y: 1, z: 0 };
|
||||
pitchNormal = { x: 1, y: 0, z: 0 };
|
||||
rollNormal = { x: 0, y: 0, z: 1 };
|
||||
|
||||
yawCorner = { x: right + rotateHandleOffset,
|
||||
y: bottom - rotateHandleOffset,
|
||||
z: near - rotateHandleOffset };
|
||||
|
||||
pitchCorner = { x: right + rotateHandleOffset,
|
||||
y: top + rotateHandleOffset,
|
||||
z: far + rotateHandleOffset };
|
||||
|
||||
rollCorner = { x: left - rotateHandleOffset,
|
||||
pitchCorner = { x: left - rotateHandleOffset,
|
||||
y: top + rotateHandleOffset,
|
||||
z: near - rotateHandleOffset};
|
||||
|
||||
rollCorner = { x: right + rotateHandleOffset,
|
||||
y: top + rotateHandleOffset,
|
||||
z: far + rotateHandleOffset };
|
||||
|
||||
yawCenter = { x: center.x, y: bottom, z: center.z };
|
||||
pitchCenter = { x: left, y: center.y, z: center.z};
|
||||
rollCenter = { x: center.x, y: center.y, z: far };
|
||||
|
||||
|
||||
Overlays.editOverlay(pitchHandle, { url: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/rotate-arrow-west-south.png" });
|
||||
Overlays.editOverlay(rollHandle, { url: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/rotate-arrow-west-south.png" });
|
||||
|
||||
|
||||
} else {
|
||||
yawHandleRotation = Quat.fromVec3Degrees({ x: 90, y: 270, z: 0 });
|
||||
yawHandleRotation = Quat.fromVec3Degrees({ x: 270, y: 0, z: 0 });
|
||||
pitchHandleRotation = Quat.fromVec3Degrees({ x: 180, y: 270, z: 0 });
|
||||
rollHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 90 });
|
||||
|
||||
yawNormal = { x: 0, y: 1, z: 0 };
|
||||
pitchNormal = { x: 1, y: 0, z: 0 };
|
||||
rollNormal = { x: 0, y: 0, z: 1 };
|
||||
|
||||
|
||||
yawCorner = { x: right + rotateHandleOffset,
|
||||
y: bottom - rotateHandleOffset,
|
||||
z: far + rotateHandleOffset };
|
||||
|
@ -465,14 +542,25 @@ SelectionDisplay = (function () {
|
|||
y: top + rotateHandleOffset,
|
||||
z: near - rotateHandleOffset};
|
||||
|
||||
|
||||
yawCenter = { x: center.x, y: bottom, z: center.z };
|
||||
pitchCenter = { x: left, y: center.y, z: center.z };
|
||||
rollCenter = { x: center.x, y: center.y, z: near};
|
||||
|
||||
Overlays.editOverlay(pitchHandle, { url: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/rotate-arrow-west-north.png" });
|
||||
Overlays.editOverlay(rollHandle, { url: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/rotate-arrow-west-north.png" });
|
||||
}
|
||||
} else {
|
||||
// must be BLF or BLN
|
||||
if (MyAvatar.position.z < center.z) {
|
||||
yawHandleRotation = Quat.fromVec3Degrees({ x: 90, y: 90, z: 0 });
|
||||
yawHandleRotation = Quat.fromVec3Degrees({ x: 270, y: 180, z: 0 });
|
||||
pitchHandleRotation = Quat.fromVec3Degrees({ x: 90, y: 0, z: 90 });
|
||||
rollHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 180 });
|
||||
|
||||
yawNormal = { x: 0, y: 1, z: 0 };
|
||||
pitchNormal = { x: 1, y: 0, z: 0 };
|
||||
rollNormal = { x: 0, y: 0, z: 1 };
|
||||
|
||||
yawCorner = { x: left - rotateHandleOffset,
|
||||
y: bottom - rotateHandleOffset,
|
||||
z: near - rotateHandleOffset };
|
||||
|
@ -485,68 +573,106 @@ SelectionDisplay = (function () {
|
|||
y: top + rotateHandleOffset,
|
||||
z: far + rotateHandleOffset};
|
||||
|
||||
|
||||
yawCenter = { x: center.x, y: bottom, z: center.z };
|
||||
pitchCenter = { x: right, y: center.y, z: center.z };
|
||||
rollCenter = { x: center.x, y: center.y, z: far};
|
||||
|
||||
Overlays.editOverlay(pitchHandle, { url: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/rotate-arrow-west-north.png" });
|
||||
Overlays.editOverlay(rollHandle, { url: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/rotate-arrow-west-north.png" });
|
||||
|
||||
} else {
|
||||
yawHandleRotation = Quat.fromVec3Degrees({ x: 90, y: 180, z: 0 });
|
||||
pitchHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 180 });
|
||||
rollHandleRotation = Quat.fromVec3Degrees({ x: 180, y: 270, z: 0 });
|
||||
yawHandleRotation = Quat.fromVec3Degrees({ x: 270, y: 270, z: 0 });
|
||||
rollHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 180 });
|
||||
pitchHandleRotation = Quat.fromVec3Degrees({ x: 180, y: 270, z: 0 });
|
||||
|
||||
yawNormal = { x: 0, y: 1, z: 0 };
|
||||
rollNormal = { x: 0, y: 0, z: 1 };
|
||||
pitchNormal = { x: 1, y: 0, z: 0 };
|
||||
|
||||
yawCorner = { x: left - rotateHandleOffset,
|
||||
y: bottom - rotateHandleOffset,
|
||||
z: far + rotateHandleOffset };
|
||||
|
||||
pitchCorner = { x: left - rotateHandleOffset,
|
||||
rollCorner = { x: left - rotateHandleOffset,
|
||||
y: top + rotateHandleOffset,
|
||||
z: near - rotateHandleOffset };
|
||||
|
||||
rollCorner = { x: right + rotateHandleOffset,
|
||||
pitchCorner = { x: right + rotateHandleOffset,
|
||||
y: top + rotateHandleOffset,
|
||||
z: far + rotateHandleOffset};
|
||||
|
||||
yawCenter = { x: center.x, y: bottom, z: center.z };
|
||||
rollCenter = { x: center.x, y: center.y, z: near };
|
||||
pitchCenter = { x: right, y: center.y, z: center.z};
|
||||
|
||||
Overlays.editOverlay(pitchHandle, { url: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/rotate-arrow-west-north.png" });
|
||||
Overlays.editOverlay(rollHandle, { url: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/rotate-arrow-west-north.png" });
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var rotateHandlesVisible = true;
|
||||
var translateHandlesVisible = true;
|
||||
var stretchHandlesVisible = true;
|
||||
var selectionBoxVisible = true;
|
||||
if (mode == "ROTATE_YAW" || mode == "ROTATE_PITCH" || mode == "ROTATE_ROLL" || mode == "TRANSLATE_XZ") {
|
||||
rotateHandlesVisible = false;
|
||||
translateHandlesVisible = false;
|
||||
stretchHandlesVisible = false;
|
||||
selectionBoxVisible = false;
|
||||
} else if (mode == "TRANSLATE_UP_DOWN") {
|
||||
rotateHandlesVisible = false;
|
||||
stretchHandlesVisible = false;
|
||||
} else if (mode != "UNKNOWN") {
|
||||
// every other mode is a stretch mode...
|
||||
rotateHandlesVisible = false;
|
||||
translateHandlesVisible = false;
|
||||
}
|
||||
|
||||
Overlays.editOverlay(highlightBox, { visible: false });
|
||||
|
||||
print("selectionBoxVisible:" + selectionBoxVisible);
|
||||
Overlays.editOverlay(selectionBox,
|
||||
{
|
||||
visible: true,
|
||||
visible: selectionBoxVisible,
|
||||
position: center,
|
||||
dimensions: properties.dimensions,
|
||||
rotation: properties.rotation,
|
||||
});
|
||||
|
||||
|
||||
Overlays.editOverlay(grabberMoveUp, { visible: true, position: { x: center.x, y: top + grabberMoveUpOffset, z: center.z } });
|
||||
Overlays.editOverlay(grabberMoveUp, { visible: translateHandlesVisible, position: { x: center.x, y: top + grabberMoveUpOffset, z: center.z } });
|
||||
|
||||
Overlays.editOverlay(grabberLBN, { visible: true, position: { x: left, y: bottom, z: near } });
|
||||
Overlays.editOverlay(grabberRBN, { visible: true, position: { x: right, y: bottom, z: near } });
|
||||
Overlays.editOverlay(grabberLBF, { visible: true, position: { x: left, y: bottom, z: far } });
|
||||
Overlays.editOverlay(grabberRBF, { visible: true, position: { x: right, y: bottom, z: far } });
|
||||
Overlays.editOverlay(grabberLTN, { visible: true, position: { x: left, y: top, z: near } });
|
||||
Overlays.editOverlay(grabberRTN, { visible: true, position: { x: right, y: top, z: near } });
|
||||
Overlays.editOverlay(grabberLTF, { visible: true, position: { x: left, y: top, z: far } });
|
||||
Overlays.editOverlay(grabberRTF, { visible: true, position: { x: right, y: top, z: far } });
|
||||
Overlays.editOverlay(grabberLBN, { visible: stretchHandlesVisible, position: { x: left, y: bottom, z: near } });
|
||||
Overlays.editOverlay(grabberRBN, { visible: stretchHandlesVisible, position: { x: right, y: bottom, z: near } });
|
||||
Overlays.editOverlay(grabberLBF, { visible: stretchHandlesVisible, position: { x: left, y: bottom, z: far } });
|
||||
Overlays.editOverlay(grabberRBF, { visible: stretchHandlesVisible, position: { x: right, y: bottom, z: far } });
|
||||
Overlays.editOverlay(grabberLTN, { visible: stretchHandlesVisible, position: { x: left, y: top, z: near } });
|
||||
Overlays.editOverlay(grabberRTN, { visible: stretchHandlesVisible, position: { x: right, y: top, z: near } });
|
||||
Overlays.editOverlay(grabberLTF, { visible: stretchHandlesVisible, position: { x: left, y: top, z: far } });
|
||||
Overlays.editOverlay(grabberRTF, { visible: stretchHandlesVisible, position: { x: right, y: top, z: far } });
|
||||
|
||||
|
||||
Overlays.editOverlay(grabberTOP, { visible: true, position: { x: center.x, y: top, z: center.z } });
|
||||
Overlays.editOverlay(grabberBOTTOM, { visible: true, position: { x: center.x, y: bottom, z: center.z } });
|
||||
Overlays.editOverlay(grabberLEFT, { visible: true, position: { x: left, y: center.y, z: center.z } });
|
||||
Overlays.editOverlay(grabberRIGHT, { visible: true, position: { x: right, y: center.y, z: center.z } });
|
||||
Overlays.editOverlay(grabberNEAR, { visible: true, position: { x: center.x, y: center.y, z: near } });
|
||||
Overlays.editOverlay(grabberFAR, { visible: true, position: { x: center.x, y: center.y, z: far } });
|
||||
Overlays.editOverlay(grabberTOP, { visible: stretchHandlesVisible, position: { x: center.x, y: top, z: center.z } });
|
||||
Overlays.editOverlay(grabberBOTTOM, { visible: stretchHandlesVisible, position: { x: center.x, y: bottom, z: center.z } });
|
||||
Overlays.editOverlay(grabberLEFT, { visible: stretchHandlesVisible, position: { x: left, y: center.y, z: center.z } });
|
||||
Overlays.editOverlay(grabberRIGHT, { visible: stretchHandlesVisible, position: { x: right, y: center.y, z: center.z } });
|
||||
Overlays.editOverlay(grabberNEAR, { visible: stretchHandlesVisible, position: { x: center.x, y: center.y, z: near } });
|
||||
Overlays.editOverlay(grabberFAR, { visible: stretchHandlesVisible, position: { x: center.x, y: center.y, z: far } });
|
||||
|
||||
Overlays.editOverlay(grabberEdgeTR, { visible: true, position: { x: right, y: top, z: center.z } });
|
||||
Overlays.editOverlay(grabberEdgeTL, { visible: true, position: { x: left, y: top, z: center.z } });
|
||||
Overlays.editOverlay(grabberEdgeTF, { visible: true, position: { x: center.x, y: top, z: far } });
|
||||
Overlays.editOverlay(grabberEdgeTN, { visible: true, position: { x: center.x, y: top, z: near } });
|
||||
Overlays.editOverlay(grabberEdgeBR, { visible: true, position: { x: right, y: bottom, z: center.z } });
|
||||
Overlays.editOverlay(grabberEdgeBL, { visible: true, position: { x: left, y: bottom, z: center.z } });
|
||||
Overlays.editOverlay(grabberEdgeBF, { visible: true, position: { x: center.x, y: bottom, z: far } });
|
||||
Overlays.editOverlay(grabberEdgeBN, { visible: true, position: { x: center.x, y: bottom, z: near } });
|
||||
Overlays.editOverlay(grabberEdgeNR, { visible: true, position: { x: right, y: center.y, z: near } });
|
||||
Overlays.editOverlay(grabberEdgeNL, { visible: true, position: { x: left, y: center.y, z: near } });
|
||||
Overlays.editOverlay(grabberEdgeFR, { visible: true, position: { x: right, y: center.y, z: far } });
|
||||
Overlays.editOverlay(grabberEdgeFL, { visible: true, position: { x: left, y: center.y, z: far } });
|
||||
Overlays.editOverlay(grabberEdgeTR, { visible: stretchHandlesVisible, position: { x: right, y: top, z: center.z } });
|
||||
Overlays.editOverlay(grabberEdgeTL, { visible: stretchHandlesVisible, position: { x: left, y: top, z: center.z } });
|
||||
Overlays.editOverlay(grabberEdgeTF, { visible: stretchHandlesVisible, position: { x: center.x, y: top, z: far } });
|
||||
Overlays.editOverlay(grabberEdgeTN, { visible: stretchHandlesVisible, position: { x: center.x, y: top, z: near } });
|
||||
Overlays.editOverlay(grabberEdgeBR, { visible: stretchHandlesVisible, position: { x: right, y: bottom, z: center.z } });
|
||||
Overlays.editOverlay(grabberEdgeBL, { visible: stretchHandlesVisible, position: { x: left, y: bottom, z: center.z } });
|
||||
Overlays.editOverlay(grabberEdgeBF, { visible: stretchHandlesVisible, position: { x: center.x, y: bottom, z: far } });
|
||||
Overlays.editOverlay(grabberEdgeBN, { visible: stretchHandlesVisible, position: { x: center.x, y: bottom, z: near } });
|
||||
Overlays.editOverlay(grabberEdgeNR, { visible: stretchHandlesVisible, position: { x: right, y: center.y, z: near } });
|
||||
Overlays.editOverlay(grabberEdgeNL, { visible: stretchHandlesVisible, position: { x: left, y: center.y, z: near } });
|
||||
Overlays.editOverlay(grabberEdgeFR, { visible: stretchHandlesVisible, position: { x: right, y: center.y, z: far } });
|
||||
Overlays.editOverlay(grabberEdgeFL, { visible: stretchHandlesVisible, position: { x: left, y: center.y, z: far } });
|
||||
|
||||
|
||||
Overlays.editOverlay(baseOfEntityProjectionOverlay,
|
||||
|
@ -562,14 +688,12 @@ SelectionDisplay = (function () {
|
|||
rotation: properties.rotation,
|
||||
});
|
||||
|
||||
|
||||
Overlays.editOverlay(rotateOverlayTarget, { visible: false });
|
||||
|
||||
Overlays.editOverlay(rotateOverlayInner,
|
||||
{
|
||||
visible: false,
|
||||
position: { x: properties.position.x,
|
||||
y: properties.position.y - (properties.dimensions.y / 2),
|
||||
z: properties.position.z},
|
||||
|
||||
size: innerRadius,
|
||||
innerRadius: 0.9,
|
||||
alpha: innerAlpha
|
||||
|
@ -578,10 +702,6 @@ SelectionDisplay = (function () {
|
|||
Overlays.editOverlay(rotateOverlayOuter,
|
||||
{
|
||||
visible: false,
|
||||
position: { x: properties.position.x,
|
||||
y: properties.position.y - (properties.dimensions.y / 2),
|
||||
z: properties.position.z},
|
||||
|
||||
size: outerRadius,
|
||||
innerRadius: 0.9,
|
||||
startAt: 0,
|
||||
|
@ -592,20 +712,19 @@ SelectionDisplay = (function () {
|
|||
Overlays.editOverlay(rotateOverlayCurrent,
|
||||
{
|
||||
visible: false,
|
||||
position: { x: properties.position.x,
|
||||
y: properties.position.y - (properties.dimensions.y / 2),
|
||||
z: properties.position.z},
|
||||
|
||||
size: outerRadius,
|
||||
startAt: 0,
|
||||
endAt: 0,
|
||||
innerRadius: 0.9,
|
||||
});
|
||||
|
||||
Overlays.editOverlay(rotateZeroOverlay, { visible: false });
|
||||
Overlays.editOverlay(rotateCurrentOverlay, { visible: false });
|
||||
|
||||
// TODO: we have not implemented the rotating handle/controls yet... so for now, these handles are hidden
|
||||
Overlays.editOverlay(yawHandle, { visible: false, position: yawCorner, rotation: yawHandleRotation});
|
||||
Overlays.editOverlay(pitchHandle, { visible: false, position: pitchCorner, rotation: pitchHandleRotation});
|
||||
Overlays.editOverlay(rollHandle, { visible: false, position: rollCorner, rotation: rollHandleRotation});
|
||||
Overlays.editOverlay(yawHandle, { visible: rotateHandlesVisible, position: yawCorner, rotation: yawHandleRotation});
|
||||
Overlays.editOverlay(pitchHandle, { visible: rotateHandlesVisible, position: pitchCorner, rotation: pitchHandleRotation});
|
||||
Overlays.editOverlay(rollHandle, { visible: rotateHandlesVisible, position: rollCorner, rotation: rollHandleRotation});
|
||||
|
||||
Entities.editEntity(entityID, { localRenderAlpha: 0.1 });
|
||||
};
|
||||
|
@ -655,10 +774,14 @@ SelectionDisplay = (function () {
|
|||
Overlays.editOverlay(pitchHandle, { visible: false });
|
||||
Overlays.editOverlay(rollHandle, { visible: false });
|
||||
|
||||
Overlays.editOverlay(rotateOverlayTarget, { visible: false });
|
||||
Overlays.editOverlay(rotateOverlayInner, { visible: false });
|
||||
Overlays.editOverlay(rotateOverlayOuter, { visible: false });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { visible: false });
|
||||
|
||||
Overlays.editOverlay(rotateZeroOverlay, { visible: false });
|
||||
Overlays.editOverlay(rotateCurrentOverlay, { visible: false });
|
||||
|
||||
Entities.editEntity(entityID, { localRenderAlpha: 1.0 });
|
||||
|
||||
currentSelection = { id: -1, isKnownID: false };
|
||||
|
@ -1440,7 +1563,185 @@ SelectionDisplay = (function () {
|
|||
Entities.editEntity(currentSelection, selectedEntityProperties);
|
||||
tooltip.updateText(selectedEntityProperties);
|
||||
that.select(currentSelection, false); // TODO: this should be more than highlighted
|
||||
};
|
||||
};
|
||||
|
||||
that.rotateYaw = function(event) {
|
||||
if (!entitySelected || mode !== "ROTATE_YAW") {
|
||||
return; // not allowed
|
||||
}
|
||||
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false});
|
||||
Overlays.editOverlay(baseOfEntityProjectionOverlay, { ignoreRayIntersection: true, visible: false });
|
||||
Overlays.editOverlay(rotateOverlayTarget, { ignoreRayIntersection: false });
|
||||
Overlays.editOverlay(rotateOverlayInner, { ignoreRayIntersection: true });
|
||||
Overlays.editOverlay(rotateOverlayOuter, { ignoreRayIntersection: true });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { ignoreRayIntersection: true });
|
||||
|
||||
var result = Overlays.findRayIntersection(pickRay);
|
||||
if (result.intersects) {
|
||||
var properties = Entities.getEntityProperties(currentSelection);
|
||||
var center = yawCenter;
|
||||
var zero = yawZero;
|
||||
var centerToZero = Vec3.subtract(center, zero);
|
||||
var centerToIntersect = Vec3.subtract(center, result.intersection);
|
||||
var angleFromZero = Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal);
|
||||
|
||||
var distanceFromCenter = Vec3.distance(center, result.intersection);
|
||||
var snapToInner = false;
|
||||
if (distanceFromCenter < innerRadius) {
|
||||
angleFromZero = Math.floor(angleFromZero/innerSnapAngle) * innerSnapAngle;
|
||||
snapToInner = true;
|
||||
}
|
||||
|
||||
// for debugging
|
||||
//Overlays.editOverlay(rotateCurrentOverlay, { visible: true, start: center, end: result.intersection });
|
||||
|
||||
var yawChange = Quat.fromVec3Degrees({ x: 0, y: angleFromZero, z: 0 });
|
||||
var newRotation = Quat.multiply(yawChange, originalRotation);
|
||||
|
||||
Entities.editEntity(currentSelection, { rotation: newRotation });
|
||||
|
||||
// update the rotation display accordingly...
|
||||
var startAtCurrent = 0;
|
||||
var endAtCurrent = angleFromZero;
|
||||
var startAtRemainder = angleFromZero;
|
||||
var endAtRemainder = 360;
|
||||
if (angleFromZero < 0) {
|
||||
startAtCurrent = 360 + angleFromZero;
|
||||
endAtCurrent = 360;
|
||||
startAtRemainder = 0;
|
||||
endAtRemainder = startAtCurrent;
|
||||
}
|
||||
if (snapToInner) {
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius });
|
||||
} else {
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius });
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
that.rotatePitch = function(event) {
|
||||
if (!entitySelected || mode !== "ROTATE_PITCH") {
|
||||
return; // not allowed
|
||||
}
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false});
|
||||
Overlays.editOverlay(baseOfEntityProjectionOverlay, { ignoreRayIntersection: true, visible: false });
|
||||
Overlays.editOverlay(rotateOverlayTarget, { ignoreRayIntersection: false });
|
||||
Overlays.editOverlay(rotateOverlayInner, { ignoreRayIntersection: true });
|
||||
Overlays.editOverlay(rotateOverlayOuter, { ignoreRayIntersection: true });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { ignoreRayIntersection: true });
|
||||
var result = Overlays.findRayIntersection(pickRay);
|
||||
|
||||
if (result.intersects) {
|
||||
var properties = Entities.getEntityProperties(currentSelection);
|
||||
var center = pitchCenter;
|
||||
var zero = pitchZero;
|
||||
var centerToZero = Vec3.subtract(center, zero);
|
||||
var centerToIntersect = Vec3.subtract(center, result.intersection);
|
||||
var angleFromZero = Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal);
|
||||
|
||||
var distanceFromCenter = Vec3.distance(center, result.intersection);
|
||||
var snapToInner = false;
|
||||
if (distanceFromCenter < innerRadius) {
|
||||
angleFromZero = Math.floor(angleFromZero/innerSnapAngle) * innerSnapAngle;
|
||||
snapToInner = true;
|
||||
}
|
||||
|
||||
// for debugging
|
||||
//Overlays.editOverlay(rotateCurrentOverlay, { visible: true, start: center, end: result.intersection });
|
||||
|
||||
var pitchChange = Quat.fromVec3Degrees({ x: angleFromZero, y: 0, z: 0 });
|
||||
var newRotation = Quat.multiply(pitchChange, originalRotation);
|
||||
|
||||
Entities.editEntity(currentSelection, { rotation: newRotation });
|
||||
|
||||
// update the rotation display accordingly...
|
||||
var startAtCurrent = 0;
|
||||
var endAtCurrent = angleFromZero;
|
||||
var startAtRemainder = angleFromZero;
|
||||
var endAtRemainder = 360;
|
||||
if (angleFromZero < 0) {
|
||||
startAtCurrent = 360 + angleFromZero;
|
||||
endAtCurrent = 360;
|
||||
startAtRemainder = 0;
|
||||
endAtRemainder = startAtCurrent;
|
||||
}
|
||||
if (snapToInner) {
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius });
|
||||
} else {
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
that.rotateRoll = function(event) {
|
||||
if (!entitySelected || mode !== "ROTATE_ROLL") {
|
||||
return; // not allowed
|
||||
}
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false});
|
||||
Overlays.editOverlay(baseOfEntityProjectionOverlay, { ignoreRayIntersection: true, visible: false });
|
||||
Overlays.editOverlay(rotateOverlayTarget, { ignoreRayIntersection: false });
|
||||
Overlays.editOverlay(rotateOverlayInner, { ignoreRayIntersection: true });
|
||||
Overlays.editOverlay(rotateOverlayOuter, { ignoreRayIntersection: true });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { ignoreRayIntersection: true });
|
||||
var result = Overlays.findRayIntersection(pickRay);
|
||||
if (result.intersects) {
|
||||
var properties = Entities.getEntityProperties(currentSelection);
|
||||
var center = rollCenter;
|
||||
var zero = rollZero;
|
||||
var centerToZero = Vec3.subtract(center, zero);
|
||||
var centerToIntersect = Vec3.subtract(center, result.intersection);
|
||||
var angleFromZero = Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal);
|
||||
|
||||
var distanceFromCenter = Vec3.distance(center, result.intersection);
|
||||
var snapToInner = false;
|
||||
if (distanceFromCenter < innerRadius) {
|
||||
angleFromZero = Math.floor(angleFromZero/innerSnapAngle) * innerSnapAngle;
|
||||
snapToInner = true;
|
||||
}
|
||||
|
||||
// for debugging
|
||||
//Overlays.editOverlay(rotateCurrentOverlay, { visible: true, start: center, end: result.intersection });
|
||||
|
||||
var rollChange = Quat.fromVec3Degrees({ x: 0, y: 0, z: angleFromZero });
|
||||
var newRotation = Quat.multiply(rollChange, originalRotation);
|
||||
|
||||
Entities.editEntity(currentSelection, { rotation: newRotation });
|
||||
|
||||
// update the rotation display accordingly...
|
||||
var startAtCurrent = 0;
|
||||
var endAtCurrent = angleFromZero;
|
||||
var startAtRemainder = angleFromZero;
|
||||
var endAtRemainder = 360;
|
||||
if (angleFromZero < 0) {
|
||||
startAtCurrent = 360 + angleFromZero;
|
||||
endAtCurrent = 360;
|
||||
startAtRemainder = 0;
|
||||
endAtRemainder = startAtCurrent;
|
||||
}
|
||||
if (snapToInner) {
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius });
|
||||
} else {
|
||||
Overlays.editOverlay(rotateOverlayInner, { startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayOuter, { startAt: startAtRemainder, endAt: endAtRemainder });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
that.checkMove = function() {
|
||||
if (currentSelection.isKnownID &&
|
||||
|
@ -1477,6 +1778,36 @@ SelectionDisplay = (function () {
|
|||
case grabberMoveUp:
|
||||
mode = "TRANSLATE_UP_DOWN";
|
||||
somethingClicked = true;
|
||||
|
||||
// in translate mode, we hide our stretch handles...
|
||||
Overlays.editOverlay(grabberLBN, { visible: false });
|
||||
Overlays.editOverlay(grabberLBF, { visible: false });
|
||||
Overlays.editOverlay(grabberRBN, { visible: false });
|
||||
Overlays.editOverlay(grabberRBF, { visible: false });
|
||||
Overlays.editOverlay(grabberLTN, { visible: false });
|
||||
Overlays.editOverlay(grabberLTF, { visible: false });
|
||||
Overlays.editOverlay(grabberRTN, { visible: false });
|
||||
Overlays.editOverlay(grabberRTF, { visible: false });
|
||||
|
||||
Overlays.editOverlay(grabberTOP, { visible: false });
|
||||
Overlays.editOverlay(grabberBOTTOM, { visible: false });
|
||||
Overlays.editOverlay(grabberLEFT, { visible: false });
|
||||
Overlays.editOverlay(grabberRIGHT, { visible: false });
|
||||
Overlays.editOverlay(grabberNEAR, { visible: false });
|
||||
Overlays.editOverlay(grabberFAR, { visible: false });
|
||||
|
||||
Overlays.editOverlay(grabberEdgeTR, { visible: false });
|
||||
Overlays.editOverlay(grabberEdgeTL, { visible: false });
|
||||
Overlays.editOverlay(grabberEdgeTF, { visible: false });
|
||||
Overlays.editOverlay(grabberEdgeTN, { visible: false });
|
||||
Overlays.editOverlay(grabberEdgeBR, { visible: false });
|
||||
Overlays.editOverlay(grabberEdgeBL, { visible: false });
|
||||
Overlays.editOverlay(grabberEdgeBF, { visible: false });
|
||||
Overlays.editOverlay(grabberEdgeBN, { visible: false });
|
||||
Overlays.editOverlay(grabberEdgeNR, { visible: false });
|
||||
Overlays.editOverlay(grabberEdgeNL, { visible: false });
|
||||
Overlays.editOverlay(grabberEdgeFR, { visible: false });
|
||||
Overlays.editOverlay(grabberEdgeFL, { visible: false });
|
||||
break;
|
||||
|
||||
case grabberRBN:
|
||||
|
@ -1559,20 +1890,131 @@ SelectionDisplay = (function () {
|
|||
}
|
||||
}
|
||||
|
||||
// if one of the items above was clicked, then we know we are in translate or stretch mode, and we
|
||||
// should hide our rotate handles...
|
||||
if (somethingClicked) {
|
||||
Overlays.editOverlay(yawHandle, { visible: false });
|
||||
Overlays.editOverlay(pitchHandle, { visible: false });
|
||||
Overlays.editOverlay(rollHandle, { visible: false });
|
||||
|
||||
if (mode != "TRANSLATE_UP_DOWN") {
|
||||
Overlays.editOverlay(grabberMoveUp, { visible: false });
|
||||
}
|
||||
}
|
||||
|
||||
if (!somethingClicked) {
|
||||
|
||||
print("rotate handle case...");
|
||||
|
||||
// After testing our stretch handles, then check out rotate handles
|
||||
Overlays.editOverlay(yawHandle, { ignoreRayIntersection: false });
|
||||
Overlays.editOverlay(pitchHandle, { ignoreRayIntersection: false });
|
||||
Overlays.editOverlay(rollHandle, { ignoreRayIntersection: false });
|
||||
var result = Overlays.findRayIntersection(pickRay);
|
||||
|
||||
var overlayOrientation;
|
||||
var overlayCenter;
|
||||
|
||||
var properties = Entities.getEntityProperties(currentSelection);
|
||||
var angles = Quat.safeEulerAngles(properties.rotation);
|
||||
var pitch = angles.x;
|
||||
var yaw = angles.y;
|
||||
var roll = angles.z;
|
||||
|
||||
originalRotation = properties.rotation;
|
||||
originalPitch = pitch;
|
||||
originalYaw = yaw;
|
||||
originalRoll = roll;
|
||||
|
||||
if (result.intersects) {
|
||||
switch(result.overlayID) {
|
||||
case yawHandle:
|
||||
mode = "ROTATE_YAW";
|
||||
somethingClicked = true;
|
||||
overlayOrientation = yawHandleRotation;
|
||||
overlayCenter = yawCenter;
|
||||
yawZero = result.intersection;
|
||||
rotationNormal = yawNormal;
|
||||
break;
|
||||
|
||||
case pitchHandle:
|
||||
mode = "ROTATE_PITCH";
|
||||
somethingClicked = true;
|
||||
overlayOrientation = pitchHandleRotation;
|
||||
overlayCenter = pitchCenter;
|
||||
pitchZero = result.intersection;
|
||||
rotationNormal = pitchNormal;
|
||||
break;
|
||||
|
||||
case rollHandle:
|
||||
mode = "ROTATE_ROLL";
|
||||
somethingClicked = true;
|
||||
overlayOrientation = rollHandleRotation;
|
||||
overlayCenter = rollCenter;
|
||||
rollZero = result.intersection;
|
||||
rotationNormal = rollNormal;
|
||||
break;
|
||||
|
||||
default:
|
||||
print("mousePressEvent()...... " + overlayNames[result.overlayID]);
|
||||
mode = "UNKNOWN";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
print(" somethingClicked:" + somethingClicked);
|
||||
print(" mode:" + mode);
|
||||
|
||||
|
||||
if (somethingClicked) {
|
||||
|
||||
Overlays.editOverlay(rotateOverlayTarget, { visible: true, rotation: overlayOrientation, position: overlayCenter });
|
||||
Overlays.editOverlay(rotateOverlayInner, { visible: true, rotation: overlayOrientation, position: overlayCenter });
|
||||
Overlays.editOverlay(rotateOverlayOuter, { visible: true, rotation: overlayOrientation, position: overlayCenter, startAt: 0, endAt: 360 });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { visible: true, rotation: overlayOrientation, position: overlayCenter, startAt: 0, endAt: 0 });
|
||||
|
||||
// for debugging
|
||||
//Overlays.editOverlay(rotateZeroOverlay, { visible: true, start: overlayCenter, end: result.intersection });
|
||||
//Overlays.editOverlay(rotateCurrentOverlay, { visible: true, start: overlayCenter, end: result.intersection });
|
||||
|
||||
Overlays.editOverlay(yawHandle, { visible: false });
|
||||
Overlays.editOverlay(pitchHandle, { visible: false });
|
||||
Overlays.editOverlay(rollHandle, { visible: false });
|
||||
|
||||
|
||||
Overlays.editOverlay(yawHandle, { visible: false });
|
||||
Overlays.editOverlay(pitchHandle, { visible: false });
|
||||
Overlays.editOverlay(rollHandle, { visible: false });
|
||||
Overlays.editOverlay(grabberMoveUp, { visible: false });
|
||||
Overlays.editOverlay(grabberLBN, { visible: false });
|
||||
Overlays.editOverlay(grabberLBF, { visible: false });
|
||||
Overlays.editOverlay(grabberRBN, { visible: false });
|
||||
Overlays.editOverlay(grabberRBF, { visible: false });
|
||||
Overlays.editOverlay(grabberLTN, { visible: false });
|
||||
Overlays.editOverlay(grabberLTF, { visible: false });
|
||||
Overlays.editOverlay(grabberRTN, { visible: false });
|
||||
Overlays.editOverlay(grabberRTF, { visible: false });
|
||||
|
||||
Overlays.editOverlay(grabberTOP, { visible: false });
|
||||
Overlays.editOverlay(grabberBOTTOM, { visible: false });
|
||||
Overlays.editOverlay(grabberLEFT, { visible: false });
|
||||
Overlays.editOverlay(grabberRIGHT, { visible: false });
|
||||
Overlays.editOverlay(grabberNEAR, { visible: false });
|
||||
Overlays.editOverlay(grabberFAR, { visible: false });
|
||||
|
||||
Overlays.editOverlay(grabberEdgeTR, { visible: false });
|
||||
Overlays.editOverlay(grabberEdgeTL, { visible: false });
|
||||
Overlays.editOverlay(grabberEdgeTF, { visible: false });
|
||||
Overlays.editOverlay(grabberEdgeTN, { visible: false });
|
||||
Overlays.editOverlay(grabberEdgeBR, { visible: false });
|
||||
Overlays.editOverlay(grabberEdgeBL, { visible: false });
|
||||
Overlays.editOverlay(grabberEdgeBF, { visible: false });
|
||||
Overlays.editOverlay(grabberEdgeBN, { visible: false });
|
||||
Overlays.editOverlay(grabberEdgeNR, { visible: false });
|
||||
Overlays.editOverlay(grabberEdgeNL, { visible: false });
|
||||
Overlays.editOverlay(grabberEdgeFR, { visible: false });
|
||||
Overlays.editOverlay(grabberEdgeFL, { visible: false });
|
||||
}
|
||||
}
|
||||
|
||||
if (!somethingClicked) {
|
||||
|
@ -1614,6 +2056,15 @@ SelectionDisplay = (function () {
|
|||
that.mouseMoveEvent = function(event) {
|
||||
//print("mouseMoveEvent()... mode:" + mode);
|
||||
switch (mode) {
|
||||
case "ROTATE_YAW":
|
||||
that.rotateYaw(event);
|
||||
break;
|
||||
case "ROTATE_PITCH":
|
||||
that.rotatePitch(event);
|
||||
break;
|
||||
case "ROTATE_ROLL":
|
||||
that.rotateRoll(event);
|
||||
break;
|
||||
case "TRANSLATE_UP_DOWN":
|
||||
that.translateUpDown(event);
|
||||
break;
|
||||
|
@ -1671,14 +2122,34 @@ SelectionDisplay = (function () {
|
|||
};
|
||||
|
||||
that.mouseReleaseEvent = function(event) {
|
||||
var showHandles = false;
|
||||
// hide our rotation overlays..., and show our handles
|
||||
if (mode == "ROTATE_YAW" || mode == "ROTATE_PITCH" || mode == "ROTATE_ROLL") {
|
||||
Overlays.editOverlay(rotateOverlayTarget, { visible: false });
|
||||
Overlays.editOverlay(rotateOverlayInner, { visible: false });
|
||||
Overlays.editOverlay(rotateOverlayOuter, { visible: false });
|
||||
Overlays.editOverlay(rotateOverlayCurrent, { visible: false });
|
||||
showHandles = true;
|
||||
}
|
||||
|
||||
if (mode != "UNKNOWN") {
|
||||
showHandles = true;
|
||||
}
|
||||
|
||||
mode = "UNKNOWN";
|
||||
|
||||
// if something is selected, then reset the "original" properties for any potential next click+move operation
|
||||
if (entitySelected) {
|
||||
|
||||
if (showHandles) {
|
||||
that.select(currentSelection, event);
|
||||
}
|
||||
|
||||
selectedEntityProperties = Entities.getEntityProperties(currentSelection);
|
||||
selectedEntityPropertiesOriginalPosition = properties.position;
|
||||
selectedEntityPropertiesOriginalDimensions = properties.dimensions;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Controller.mousePressEvent.connect(that.mousePressEvent);
|
||||
|
|
|
@ -570,6 +570,19 @@ function handeMenuEvent(menuItem) {
|
|||
}
|
||||
} else if (menuItem == "Edit Properties...") {
|
||||
// good place to put the properties dialog
|
||||
|
||||
editModelID = -1;
|
||||
if (entitySelected) {
|
||||
print(" Edit Properties.... selectedEntityID="+ selectedEntityID);
|
||||
editModelID = selectedEntityID;
|
||||
} else {
|
||||
print(" Edit Properties.... not holding...");
|
||||
}
|
||||
if (editModelID != -1) {
|
||||
print(" Edit Properties.... about to edit properties...");
|
||||
entityPropertyDialogBox.openDialog(editModelID);
|
||||
}
|
||||
|
||||
} else if (menuItem == "Paste Models") {
|
||||
modelImporter.paste();
|
||||
} else if (menuItem == "Export Models") {
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
//
|
||||
// xbox.js
|
||||
// examples
|
||||
//
|
||||
// Created by Stephen Birarda on September 23, 2014
|
||||
//
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
gamepad = Joysticks.joystickWithName("Wireless 360 Controller");
|
||||
|
||||
function reportAxisValue(axis, newValue, oldValue) {
|
||||
print("The value for axis " + axis + " has changed to " + newValue + ". It was " + oldValue);
|
||||
}
|
||||
|
||||
gamepad.axisValueChanged.connect(reportAxisValue);
|
|
@ -41,7 +41,7 @@ configure_file(InterfaceVersion.h.in "${PROJECT_BINARY_DIR}/includes/InterfaceVe
|
|||
|
||||
# grab the implementation and header files from src dirs
|
||||
file(GLOB INTERFACE_SRCS src/*.cpp src/*.h)
|
||||
foreach(SUBDIR avatar devices renderer ui starfield location scripting voxels particles entities)
|
||||
foreach(SUBDIR avatar devices renderer ui starfield location scripting voxels particles entities gpu)
|
||||
file(GLOB_RECURSE SUBDIR_SRCS src/${SUBDIR}/*.cpp src/${SUBDIR}/*.h)
|
||||
set(INTERFACE_SRCS ${INTERFACE_SRCS} "${SUBDIR_SRCS}")
|
||||
endforeach(SUBDIR)
|
||||
|
|
|
@ -605,10 +605,14 @@ void Application::paintGL() {
|
|||
|
||||
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
|
||||
if (!OculusManager::isConnected()) {
|
||||
// If there isn't an HMD, match exactly to avatar's head
|
||||
_myCamera.setPosition(_myAvatar->getHead()->getEyePosition());
|
||||
_myCamera.setRotation(_myAvatar->getHead()->getCameraOrientation());
|
||||
} else {
|
||||
// For an HMD, set the base position and orientation to that of the avatar body
|
||||
_myCamera.setPosition(_myAvatar->getDefaultEyePosition());
|
||||
_myCamera.setRotation(_myAvatar->getWorldAlignedOrientation());
|
||||
}
|
||||
// OculusManager::display() updates camera position and rotation a bit further on.
|
||||
|
||||
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
|
||||
static const float THIRD_PERSON_CAMERA_DISTANCE = 1.5f;
|
||||
|
@ -664,7 +668,6 @@ void Application::paintGL() {
|
|||
|
||||
_viewFrustumOffsetCamera.setRotation(_myCamera.getRotation() * frustumRotation);
|
||||
|
||||
_viewFrustumOffsetCamera.initialize(); // force immediate snap to ideal position and orientation
|
||||
_viewFrustumOffsetCamera.update(1.f/_fps);
|
||||
whichCamera = &_viewFrustumOffsetCamera;
|
||||
}
|
||||
|
|
|
@ -22,13 +22,16 @@
|
|||
|
||||
|
||||
Camera::Camera() :
|
||||
_needsToInitialize(true),
|
||||
_mode(CAMERA_MODE_THIRD_PERSON),
|
||||
_position(0.0f, 0.0f, 0.0f),
|
||||
_fieldOfView(DEFAULT_FIELD_OF_VIEW_DEGREES),
|
||||
_aspectRatio(16.0f/9.0f),
|
||||
_nearClip(DEFAULT_NEAR_CLIP), // default
|
||||
_farClip(DEFAULT_FAR_CLIP), // default
|
||||
_hmdPosition(),
|
||||
_hmdRotation(),
|
||||
_targetPosition(),
|
||||
_targetRotation(),
|
||||
_scale(1.0f)
|
||||
{
|
||||
}
|
||||
|
@ -64,26 +67,6 @@ void Camera::setFarClip(float f) {
|
|||
_farClip = f;
|
||||
}
|
||||
|
||||
void Camera::setEyeOffsetPosition(const glm::vec3& p) {
|
||||
_eyeOffsetPosition = p;
|
||||
}
|
||||
|
||||
void Camera::setEyeOffsetOrientation(const glm::quat& o) {
|
||||
_eyeOffsetOrientation = o;
|
||||
|
||||
}
|
||||
|
||||
void Camera::setScale(float s) {
|
||||
_scale = s;
|
||||
_needsToInitialize = true;
|
||||
|
||||
}
|
||||
|
||||
void Camera::initialize() {
|
||||
_needsToInitialize = true;
|
||||
}
|
||||
|
||||
|
||||
CameraScriptableObject::CameraScriptableObject(Camera* camera, ViewFrustum* viewFrustum) :
|
||||
_camera(camera), _viewFrustum(viewFrustum)
|
||||
{
|
||||
|
|
|
@ -38,17 +38,23 @@ public:
|
|||
|
||||
void setPosition(const glm::vec3& p) { _position = p; }
|
||||
void setRotation(const glm::quat& rotation) { _rotation = rotation; };
|
||||
void setHmdPosition(const glm::vec3& hmdPosition) { _hmdPosition = hmdPosition; }
|
||||
void setHmdRotation(const glm::quat& hmdRotation) { _hmdRotation = hmdRotation; };
|
||||
|
||||
void setMode(CameraMode m);
|
||||
void setFieldOfView(float f);
|
||||
void setAspectRatio(float a);
|
||||
void setNearClip(float n);
|
||||
void setFarClip(float f);
|
||||
void setEyeOffsetPosition(const glm::vec3& p);
|
||||
void setEyeOffsetOrientation(const glm::quat& o);
|
||||
void setScale(const float s);
|
||||
void setEyeOffsetPosition(const glm::vec3& p) { _eyeOffsetPosition = p; }
|
||||
void setEyeOffsetOrientation(const glm::quat& o) { _eyeOffsetOrientation = o; }
|
||||
void setScale(const float s) { _scale = s; }
|
||||
|
||||
glm::vec3 getPosition() const { return _position + _hmdPosition; }
|
||||
glm::quat getRotation() const { return _rotation * _hmdRotation; }
|
||||
const glm::vec3& getHmdPosition() const { return _hmdPosition; }
|
||||
const glm::quat& getHmdRotation() const { return _hmdRotation; }
|
||||
|
||||
const glm::vec3& getPosition() const { return _position; }
|
||||
const glm::quat& getRotation() const { return _rotation; }
|
||||
CameraMode getMode() const { return _mode; }
|
||||
float getFieldOfView() const { return _fieldOfView; }
|
||||
float getAspectRatio() const { return _aspectRatio; }
|
||||
|
@ -60,7 +66,6 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
bool _needsToInitialize;
|
||||
CameraMode _mode;
|
||||
glm::vec3 _position;
|
||||
float _fieldOfView; // degrees
|
||||
|
@ -70,7 +75,10 @@ private:
|
|||
glm::vec3 _eyeOffsetPosition;
|
||||
glm::quat _eyeOffsetOrientation;
|
||||
glm::quat _rotation;
|
||||
|
||||
glm::vec3 _hmdPosition;
|
||||
glm::quat _hmdRotation;
|
||||
glm::vec3 _targetPosition;
|
||||
glm::quat _targetRotation;
|
||||
float _scale;
|
||||
};
|
||||
|
||||
|
|
|
@ -1151,7 +1151,7 @@ const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f;
|
|||
|
||||
bool MyAvatar::shouldRenderHead(const glm::vec3& cameraPosition, RenderMode renderMode) const {
|
||||
const Head* head = getHead();
|
||||
return (renderMode != NORMAL_RENDER_MODE) ||
|
||||
return (renderMode != NORMAL_RENDER_MODE) || (Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON) ||
|
||||
(glm::length(cameraPosition - head->getEyePosition()) > RENDER_HEAD_CUTOFF_DISTANCE * _scale);
|
||||
}
|
||||
|
||||
|
|
|
@ -337,15 +337,20 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
|
|||
#else
|
||||
ovrEyeType eye = _ovrHmdDesc.EyeRenderOrder[eyeIndex];
|
||||
#endif
|
||||
//Set the camera rotation for this eye
|
||||
// Set the camera rotation for this eye
|
||||
eyeRenderPose[eye] = ovrHmd_GetEyePose(_ovrHmd, eye);
|
||||
orientation.x = eyeRenderPose[eye].Orientation.x;
|
||||
orientation.y = eyeRenderPose[eye].Orientation.y;
|
||||
orientation.z = eyeRenderPose[eye].Orientation.z;
|
||||
orientation.w = eyeRenderPose[eye].Orientation.w;
|
||||
|
||||
_camera->setRotation(bodyOrientation * orientation);
|
||||
_camera->setPosition(position + trackerPosition);
|
||||
// Update the application camera with the latest HMD position
|
||||
whichCamera.setHmdPosition(trackerPosition);
|
||||
whichCamera.setHmdRotation(orientation);
|
||||
|
||||
// Update our camera to what the application camera is doing
|
||||
_camera->setRotation(whichCamera.getRotation());
|
||||
_camera->setPosition(whichCamera.getPosition());
|
||||
|
||||
// Store the latest left and right eye render locations for things that need to know
|
||||
glm::vec3 thisEyePosition = position + trackerPosition +
|
||||
|
@ -407,10 +412,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
|
|||
renderDistortionMesh(eyeRenderPose);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
// Update camera for use by rest of Interface.
|
||||
whichCamera.setPosition((_leftEyePosition + _rightEyePosition) / 2.f);
|
||||
whichCamera.setRotation(_camera->getRotation());
|
||||
|
||||
|
||||
#endif
|
||||
}
|
||||
|
|
220
interface/src/gpu/Resource.cpp
Normal file
220
interface/src/gpu/Resource.cpp
Normal file
|
@ -0,0 +1,220 @@
|
|||
//
|
||||
// Resource.cpp
|
||||
// interface/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 10/8/2014.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "Resource.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
Resource::Size Resource::Sysmem::allocateMemory(Byte** dataAllocated, Size size) {
|
||||
if ( !dataAllocated ) {
|
||||
qWarning() << "Buffer::Sysmem::allocateMemory() : Must have a valid dataAllocated pointer.";
|
||||
return NOT_ALLOCATED;
|
||||
}
|
||||
|
||||
// Try to allocate if needed
|
||||
Size newSize = 0;
|
||||
if (size > 0) {
|
||||
// Try allocating as much as the required size + one block of memory
|
||||
newSize = size;
|
||||
(*dataAllocated) = new Byte[newSize];
|
||||
// Failed?
|
||||
if (!(*dataAllocated)) {
|
||||
qWarning() << "Buffer::Sysmem::allocate() : Can't allocate a system memory buffer of " << newSize << "bytes. Fails to create the buffer Sysmem.";
|
||||
return NOT_ALLOCATED;
|
||||
}
|
||||
}
|
||||
|
||||
// Return what's actually allocated
|
||||
return newSize;
|
||||
}
|
||||
|
||||
void Resource::Sysmem::deallocateMemory(Byte* dataAllocated, Size size) {
|
||||
if (dataAllocated) {
|
||||
delete[] dataAllocated;
|
||||
}
|
||||
}
|
||||
|
||||
Resource::Sysmem::Sysmem() :
|
||||
_data(NULL),
|
||||
_size(0),
|
||||
_stamp(0)
|
||||
{
|
||||
}
|
||||
|
||||
Resource::Sysmem::Sysmem(Size size, const Byte* bytes) :
|
||||
_data(NULL),
|
||||
_size(0),
|
||||
_stamp(0)
|
||||
{
|
||||
if (size > 0) {
|
||||
_size = allocateMemory(&_data, size);
|
||||
if (_size >= size) {
|
||||
if (bytes) {
|
||||
memcpy(_data, bytes, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Resource::Sysmem::~Sysmem() {
|
||||
deallocateMemory( _data, _size );
|
||||
_data = NULL;
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
Resource::Size Resource::Sysmem::allocate(Size size) {
|
||||
if (size != _size) {
|
||||
Byte* newData = 0;
|
||||
Size newSize = 0;
|
||||
if (size > 0) {
|
||||
Size allocated = allocateMemory(&newData, size);
|
||||
if (allocated == NOT_ALLOCATED) {
|
||||
// early exit because allocation failed
|
||||
return 0;
|
||||
}
|
||||
newSize = allocated;
|
||||
}
|
||||
// Allocation was successful, can delete previous data
|
||||
deallocateMemory(_data, _size);
|
||||
_data = newData;
|
||||
_size = newSize;
|
||||
_stamp++;
|
||||
}
|
||||
return _size;
|
||||
}
|
||||
|
||||
Resource::Size Resource::Sysmem::resize(Size size) {
|
||||
if (size != _size) {
|
||||
Byte* newData = 0;
|
||||
Size newSize = 0;
|
||||
if (size > 0) {
|
||||
Size allocated = allocateMemory(&newData, size);
|
||||
if (allocated == NOT_ALLOCATED) {
|
||||
// early exit because allocation failed
|
||||
return _size;
|
||||
}
|
||||
newSize = allocated;
|
||||
// Restore back data from old buffer in the new one
|
||||
if (_data) {
|
||||
Size copySize = ((newSize < _size)? newSize: _size);
|
||||
memcpy( newData, _data, copySize);
|
||||
}
|
||||
}
|
||||
// Reallocation was successful, can delete previous data
|
||||
deallocateMemory(_data, _size);
|
||||
_data = newData;
|
||||
_size = newSize;
|
||||
_stamp++;
|
||||
}
|
||||
return _size;
|
||||
}
|
||||
|
||||
Resource::Size Resource::Sysmem::setData( Size size, const Byte* bytes ) {
|
||||
if (allocate(size) == size) {
|
||||
if (bytes) {
|
||||
memcpy( _data, bytes, _size );
|
||||
_stamp++;
|
||||
}
|
||||
}
|
||||
return _size;
|
||||
}
|
||||
|
||||
Resource::Size Resource::Sysmem::setSubData( Size offset, Size size, const Byte* bytes) {
|
||||
if (((offset + size) <= getSize()) && bytes) {
|
||||
memcpy( _data + offset, bytes, size );
|
||||
_stamp++;
|
||||
return size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Resource::Size Resource::Sysmem::append(Size size, const Byte* bytes) {
|
||||
if (size > 0) {
|
||||
Size oldSize = getSize();
|
||||
Size totalSize = oldSize + size;
|
||||
if (resize(totalSize) == totalSize) {
|
||||
return setSubData(oldSize, size, bytes);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Buffer::Buffer() :
|
||||
Resource(),
|
||||
_sysmem(NULL),
|
||||
_gpuObject(NULL) {
|
||||
_sysmem = new Sysmem();
|
||||
}
|
||||
|
||||
Buffer::~Buffer() {
|
||||
if (_sysmem) {
|
||||
delete _sysmem;
|
||||
_sysmem = 0;
|
||||
}
|
||||
if (_gpuObject) {
|
||||
delete _gpuObject;
|
||||
_gpuObject = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Buffer::Size Buffer::resize(Size size) {
|
||||
return editSysmem().resize(size);
|
||||
}
|
||||
|
||||
Buffer::Size Buffer::setData(Size size, const Byte* data) {
|
||||
return editSysmem().setData(size, data);
|
||||
}
|
||||
|
||||
Buffer::Size Buffer::setSubData(Size offset, Size size, const Byte* data) {
|
||||
return editSysmem().setSubData( offset, size, data);
|
||||
}
|
||||
|
||||
Buffer::Size Buffer::append(Size size, const Byte* data) {
|
||||
return editSysmem().append( size, data);
|
||||
}
|
||||
|
||||
namespace gpu {
|
||||
namespace backend {
|
||||
|
||||
BufferObject::~BufferObject() {
|
||||
if (_buffer!=0) {
|
||||
glDeleteBuffers(1, &_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void syncGPUObject(const Buffer& buffer) {
|
||||
BufferObject* object = buffer.getGPUObject();
|
||||
|
||||
if (object && (object->_stamp == buffer.getSysmem().getStamp())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// need to have a gpu object?
|
||||
if (!object) {
|
||||
object = new BufferObject();
|
||||
glGenBuffers(1, &object->_buffer);
|
||||
buffer.setGPUObject(object);
|
||||
}
|
||||
|
||||
// Now let's update the content of the bo with the sysmem version
|
||||
// TODO: in the future, be smarter about when to actually upload the glBO version based on the data that did change
|
||||
//if () {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, object->_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, buffer.getSysmem().getSize(), buffer.getSysmem().readData(), GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
object->_stamp = buffer.getSysmem().getStamp();
|
||||
object->_size = buffer.getSysmem().getSize();
|
||||
//}
|
||||
}
|
||||
|
||||
};
|
||||
};
|
166
interface/src/gpu/Resource.h
Normal file
166
interface/src/gpu/Resource.h
Normal file
|
@ -0,0 +1,166 @@
|
|||
//
|
||||
// Resource.h
|
||||
// interface/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 10/8/2014.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#ifndef hifi_gpu_Resource_h
|
||||
#define hifi_gpu_Resource_h
|
||||
|
||||
#include <assert.h>
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
namespace gpu {
|
||||
|
||||
class Buffer;
|
||||
typedef int Stamp;
|
||||
|
||||
// TODO: move the backend namespace into dedicated files, for now we keep it close to the gpu objects definition for convenience
|
||||
namespace backend {
|
||||
|
||||
class BufferObject {
|
||||
public:
|
||||
Stamp _stamp;
|
||||
GLuint _buffer;
|
||||
GLuint _size;
|
||||
|
||||
BufferObject() :
|
||||
_stamp(0),
|
||||
_buffer(0),
|
||||
_size(0)
|
||||
{}
|
||||
|
||||
~BufferObject();
|
||||
};
|
||||
void syncGPUObject(const Buffer& buffer);
|
||||
};
|
||||
|
||||
class Resource {
|
||||
public:
|
||||
typedef unsigned char Byte;
|
||||
typedef unsigned int Size;
|
||||
|
||||
static const Size NOT_ALLOCATED = -1;
|
||||
|
||||
// The size in bytes of data stored in the resource
|
||||
virtual Size getSize() const = 0;
|
||||
|
||||
protected:
|
||||
|
||||
Resource() {}
|
||||
virtual ~Resource() {}
|
||||
|
||||
// Sysmem is the underneath cache for the data in ram of a resource.
|
||||
class Sysmem {
|
||||
public:
|
||||
|
||||
Sysmem();
|
||||
Sysmem(Size size, const Byte* bytes);
|
||||
~Sysmem();
|
||||
|
||||
Size getSize() const { return _size; }
|
||||
|
||||
// Allocate the byte array
|
||||
// \param pSize The nb of bytes to allocate, if already exist, content is lost.
|
||||
// \return The nb of bytes allocated, nothing if allready the appropriate size.
|
||||
Size allocate(Size pSize);
|
||||
|
||||
// Resize the byte array
|
||||
// Keep previous data [0 to min(pSize, mSize)]
|
||||
Size resize(Size pSize);
|
||||
|
||||
// Assign data bytes and size (allocate for size, then copy bytes if exists)
|
||||
Size setData(Size size, const Byte* bytes );
|
||||
|
||||
// Update Sub data,
|
||||
// doesn't allocate and only copy size * bytes at the offset location
|
||||
// only if all fits in the existing allocated buffer
|
||||
Size setSubData(Size offset, Size size, const Byte* bytes);
|
||||
|
||||
// Append new data at the end of the current buffer
|
||||
// do a resize( size + getSIze) and copy the new data
|
||||
// \return the number of bytes copied
|
||||
Size append(Size size, const Byte* data);
|
||||
|
||||
// Access the byte array.
|
||||
// The edit version allow to map data.
|
||||
inline const Byte* readData() const { return _data; }
|
||||
inline Byte* editData() { _stamp++; return _data; }
|
||||
|
||||
template< typename T >
|
||||
const T* read() const { return reinterpret_cast< T* > ( _data ); }
|
||||
template< typename T >
|
||||
T* edit() { _stamp++; return reinterpret_cast< T* > ( _data ); }
|
||||
|
||||
// Access the current version of the sysmem, used to compare if copies are in sync
|
||||
inline Stamp getStamp() const { return _stamp; }
|
||||
|
||||
static Size allocateMemory(Byte** memAllocated, Size size);
|
||||
static void deallocateMemory(Byte* memDeallocated, Size size);
|
||||
|
||||
private:
|
||||
Sysmem(const Sysmem& sysmem) {}
|
||||
Sysmem &operator=(const Sysmem& other) {return *this;}
|
||||
|
||||
Stamp _stamp;
|
||||
Size _size;
|
||||
Byte* _data;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
class Buffer : public Resource {
|
||||
public:
|
||||
|
||||
Buffer();
|
||||
Buffer(const Buffer& buf);
|
||||
~Buffer();
|
||||
|
||||
// The size in bytes of data stored in the buffer
|
||||
inline Size getSize() const { return getSysmem().getSize(); }
|
||||
inline const Byte* getData() const { return getSysmem().readData(); }
|
||||
|
||||
// Resize the buffer
|
||||
// Keep previous data [0 to min(pSize, mSize)]
|
||||
Size resize(Size pSize);
|
||||
|
||||
// Assign data bytes and size (allocate for size, then copy bytes if exists)
|
||||
// \return the size of the buffer
|
||||
Size setData(Size size, const Byte* data);
|
||||
|
||||
// Assign data bytes and size (allocate for size, then copy bytes if exists)
|
||||
// \return the number of bytes copied
|
||||
Size setSubData(Size offset, Size size, const Byte* data);
|
||||
|
||||
// Append new data at the end of the current buffer
|
||||
// do a resize( size + getSize) and copy the new data
|
||||
// \return the number of bytes copied
|
||||
Size append(Size size, const Byte* data);
|
||||
|
||||
// this is a temporary hack so the current rendering code can access the underneath gl Buffer Object
|
||||
// TODO: remove asap, when the backend is doing more of the gl features
|
||||
inline GLuint getGLBufferObject() const { backend::syncGPUObject(*this); return getGPUObject()->_buffer; }
|
||||
|
||||
protected:
|
||||
|
||||
Sysmem* _sysmem;
|
||||
|
||||
typedef backend::BufferObject GPUObject;
|
||||
mutable backend::BufferObject* _gpuObject;
|
||||
|
||||
inline const Sysmem& getSysmem() const { assert(_sysmem); return (*_sysmem); }
|
||||
inline Sysmem& editSysmem() { assert(_sysmem); return (*_sysmem); }
|
||||
|
||||
inline GPUObject* getGPUObject() const { return _gpuObject; }
|
||||
inline void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; }
|
||||
|
||||
friend void backend::syncGPUObject(const Buffer& buffer);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -690,7 +690,6 @@ void Stats::display(
|
|||
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, reflectionsStatus, color);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Stats::setMetavoxelStats(int internal, int leaves, int sendProgress,
|
||||
|
|
|
@ -21,6 +21,10 @@
|
|||
#include "InterfaceConfig.h"
|
||||
#include "TextRenderer.h"
|
||||
|
||||
#include "glm/glm.hpp"
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
|
||||
// the width/height of the cached glyph textures
|
||||
const int IMAGE_SIZE = 256;
|
||||
|
||||
|
@ -63,8 +67,17 @@ int TextRenderer::calculateHeight(const char* str) {
|
|||
}
|
||||
|
||||
int TextRenderer::draw(int x, int y, const char* str) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
// Grab the current color
|
||||
float currentColor[4];
|
||||
glGetFloatv(GL_CURRENT_COLOR, currentColor);
|
||||
int compactColor = ((int( currentColor[0] * 255.f) & 0xFF)) |
|
||||
((int( currentColor[1] * 255.f) & 0xFF) << 8) |
|
||||
((int( currentColor[2] * 255.f) & 0xFF) << 16) |
|
||||
((int( currentColor[3] * 255.f) & 0xFF) << 24);
|
||||
|
||||
// TODO: Remove that code once we test for performance improvments
|
||||
//glEnable(GL_TEXTURE_2D);
|
||||
|
||||
int maxHeight = 0;
|
||||
for (const char* ch = str; *ch != 0; ch++) {
|
||||
const Glyph& glyph = getGlyph(*ch);
|
||||
|
@ -76,20 +89,24 @@ int TextRenderer::draw(int x, int y, const char* str) {
|
|||
if (glyph.bounds().height() > maxHeight) {
|
||||
maxHeight = glyph.bounds().height();
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, glyph.textureID());
|
||||
//glBindTexture(GL_TEXTURE_2D, glyph.textureID());
|
||||
|
||||
int left = x + glyph.bounds().x();
|
||||
int right = x + glyph.bounds().x() + glyph.bounds().width();
|
||||
int bottom = y + glyph.bounds().y();
|
||||
int top = y + glyph.bounds().y() + glyph.bounds().height();
|
||||
|
||||
|
||||
glm::vec2 leftBottom = glm::vec2(float(left), float(bottom));
|
||||
glm::vec2 rightTop = glm::vec2(float(right), float(top));
|
||||
|
||||
float scale = QApplication::desktop()->windowHandle()->devicePixelRatio() / IMAGE_SIZE;
|
||||
float ls = glyph.location().x() * scale;
|
||||
float rs = (glyph.location().x() + glyph.bounds().width()) * scale;
|
||||
float bt = glyph.location().y() * scale;
|
||||
float tt = (glyph.location().y() + glyph.bounds().height()) * scale;
|
||||
|
||||
|
||||
// TODO: Remove that code once we test for performance improvments
|
||||
/*
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(ls, bt);
|
||||
glVertex2f(left, bottom);
|
||||
|
@ -100,12 +117,39 @@ int TextRenderer::draw(int x, int y, const char* str) {
|
|||
glTexCoord2f(ls, tt);
|
||||
glVertex2f(left, top);
|
||||
glEnd();
|
||||
|
||||
*/
|
||||
|
||||
const int NUM_COORDS_SCALARS_PER_GLYPH = 16;
|
||||
float vertexBuffer[NUM_COORDS_SCALARS_PER_GLYPH] = { leftBottom.x, leftBottom.y, ls, bt,
|
||||
rightTop.x, leftBottom.y, rs, bt,
|
||||
rightTop.x, rightTop.y, rs, tt,
|
||||
leftBottom.x, rightTop.y, ls, tt, };
|
||||
|
||||
const int NUM_COLOR_SCALARS_PER_GLYPH = 4;
|
||||
unsigned int colorBuffer[NUM_COLOR_SCALARS_PER_GLYPH] = { compactColor, compactColor, compactColor, compactColor };
|
||||
|
||||
gpu::Buffer::Size offset = sizeof(vertexBuffer) * _numGlyphsBatched;
|
||||
gpu::Buffer::Size colorOffset = sizeof(colorBuffer) * _numGlyphsBatched;
|
||||
if ((offset + sizeof(vertexBuffer)) > _glyphsBuffer.getSize()) {
|
||||
_glyphsBuffer.append(sizeof(vertexBuffer), (gpu::Buffer::Byte*) vertexBuffer);
|
||||
_glyphsColorBuffer.append(sizeof(colorBuffer), (gpu::Buffer::Byte*) colorBuffer);
|
||||
} else {
|
||||
_glyphsBuffer.setSubData(offset, sizeof(vertexBuffer), (gpu::Buffer::Byte*) vertexBuffer);
|
||||
_glyphsColorBuffer.setSubData(colorOffset, sizeof(colorBuffer), (gpu::Buffer::Byte*) colorBuffer);
|
||||
}
|
||||
_numGlyphsBatched++;
|
||||
|
||||
x += glyph.width();
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
|
||||
// TODO: remove these calls once we move to a full batched rendering of the text, for now, one draw call per draw() function call
|
||||
drawBatch();
|
||||
clearBatch();
|
||||
|
||||
// TODO: Remove that code once we test for performance improvments
|
||||
// glBindTexture(GL_TEXTURE_2D, 0);
|
||||
// glDisable(GL_TEXTURE_2D);
|
||||
|
||||
return maxHeight;
|
||||
}
|
||||
|
||||
|
@ -131,8 +175,10 @@ TextRenderer::TextRenderer(const Properties& properties) :
|
|||
_x(IMAGE_SIZE),
|
||||
_y(IMAGE_SIZE),
|
||||
_rowHeight(0),
|
||||
_color(properties.color) {
|
||||
|
||||
_color(properties.color),
|
||||
_glyphsBuffer(),
|
||||
_numGlyphsBatched(0)
|
||||
{
|
||||
_font.setKerning(false);
|
||||
}
|
||||
|
||||
|
@ -228,9 +274,74 @@ const Glyph& TextRenderer::getGlyph(char c) {
|
|||
return glyph;
|
||||
}
|
||||
|
||||
void TextRenderer::drawBatch() {
|
||||
if (_numGlyphsBatched <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Right now the drawBatch is called while calling the draw() function but in the future we'll need to apply the correct transform stack
|
||||
/*
|
||||
GLint matrixMode;
|
||||
glGetIntegerv(GL_MATRIX_MODE, &matrixMode);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
*/
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
// TODO: Apply the correct font atlas texture, for now only one texture per TextRenderer so it should be good
|
||||
glBindTexture(GL_TEXTURE_2D, _currentTextureID);
|
||||
|
||||
GLuint vbo = _glyphsBuffer.getGLBufferObject();
|
||||
GLuint colorvbo = _glyphsColorBuffer.getGLBufferObject();
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
const int NUM_POS_COORDS = 2;
|
||||
const int NUM_TEX_COORDS = 2;
|
||||
const int VERTEX_STRIDE = (NUM_POS_COORDS + NUM_TEX_COORDS) * sizeof(float);
|
||||
const int VERTEX_TEXCOORD_OFFSET = NUM_POS_COORDS * sizeof(float);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
glVertexPointer(2, GL_FLOAT, VERTEX_STRIDE, 0);
|
||||
glTexCoordPointer(2, GL_FLOAT, VERTEX_STRIDE, (GLvoid*) VERTEX_TEXCOORD_OFFSET );
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, colorvbo);
|
||||
glColorPointer(4, GL_UNSIGNED_BYTE, 0, (GLvoid*) 0 );
|
||||
|
||||
glDrawArrays(GL_QUADS, 0, _numGlyphsBatched * 4);
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
// TODO: Right now the drawBatch is called while calling the draw() function but in the future we'll need to apply the correct transform stack
|
||||
/*
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPopMatrix();
|
||||
glMatrixMode(matrixMode);
|
||||
*/
|
||||
}
|
||||
|
||||
void TextRenderer::clearBatch() {
|
||||
_numGlyphsBatched = 0;
|
||||
}
|
||||
|
||||
QHash<TextRenderer::Properties, TextRenderer*> TextRenderer::_instances;
|
||||
|
||||
Glyph::Glyph(int textureID, const QPoint& location, const QRect& bounds, int width) :
|
||||
_textureID(textureID), _location(location), _bounds(bounds), _width(width) {
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include <QImage>
|
||||
#include <QVector>
|
||||
|
||||
#include "gpu/Resource.h"
|
||||
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
// a special "character" that renders as a solid block
|
||||
|
@ -64,6 +66,8 @@ public:
|
|||
int computeWidth(char ch);
|
||||
int computeWidth(const char* str);
|
||||
|
||||
void drawBatch();
|
||||
void clearBatch();
|
||||
private:
|
||||
|
||||
TextRenderer(const Properties& properties);
|
||||
|
@ -100,6 +104,11 @@ private:
|
|||
// text color
|
||||
QColor _color;
|
||||
|
||||
// Graphics Buffer containing the current accumulated glyphs to render
|
||||
gpu::Buffer _glyphsBuffer;
|
||||
gpu::Buffer _glyphsColorBuffer;
|
||||
int _numGlyphsBatched;
|
||||
|
||||
static QHash<Properties, TextRenderer*> _instances;
|
||||
};
|
||||
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
BillboardOverlay::BillboardOverlay()
|
||||
: _fromImage(-1,-1,-1,-1),
|
||||
_scale(1.0f),
|
||||
_isFacingAvatar(true) {
|
||||
_isFacingAvatar(true),
|
||||
_newTextureNeeded(true) {
|
||||
_isLoaded = false;
|
||||
}
|
||||
|
||||
|
@ -28,6 +29,9 @@ void BillboardOverlay::render() {
|
|||
}
|
||||
|
||||
if (!_billboard.isEmpty()) {
|
||||
if (_newTextureNeeded && _billboardTexture) {
|
||||
_billboardTexture.reset();
|
||||
}
|
||||
if (!_billboardTexture) {
|
||||
QImage image = QImage::fromData(_billboard);
|
||||
if (image.format() != QImage::Format_ARGB32) {
|
||||
|
@ -38,6 +42,7 @@ void BillboardOverlay::render() {
|
|||
_fromImage.setRect(0, 0, _size.width(), _size.height());
|
||||
}
|
||||
_billboardTexture.reset(new Texture());
|
||||
_newTextureNeeded = false;
|
||||
glBindTexture(GL_TEXTURE_2D, _billboardTexture->getID());
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _size.width(), _size.height(), 0,
|
||||
GL_BGRA, GL_UNSIGNED_BYTE, image.constBits());
|
||||
|
@ -107,9 +112,10 @@ void BillboardOverlay::setProperties(const QScriptValue &properties) {
|
|||
|
||||
QScriptValue urlValue = properties.property("url");
|
||||
if (urlValue.isValid()) {
|
||||
_url = urlValue.toVariant().toString();
|
||||
|
||||
setBillboardURL(_url);
|
||||
QString newURL = urlValue.toVariant().toString();
|
||||
if (newURL != _url) {
|
||||
setBillboardURL(newURL);
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue subImageBounds = properties.property("subImage");
|
||||
|
@ -150,9 +156,16 @@ void BillboardOverlay::setProperties(const QScriptValue &properties) {
|
|||
}
|
||||
}
|
||||
|
||||
void BillboardOverlay::setBillboardURL(const QUrl url) {
|
||||
void BillboardOverlay::setBillboardURL(const QString& url) {
|
||||
_url = url;
|
||||
QUrl actualURL = url;
|
||||
_isLoaded = false;
|
||||
QNetworkReply* reply = NetworkAccessManager::getInstance().get(QNetworkRequest(url));
|
||||
|
||||
// clear the billboard if previously set
|
||||
_billboard.clear();
|
||||
_newTextureNeeded = true;
|
||||
|
||||
QNetworkReply* reply = NetworkAccessManager::getInstance().get(QNetworkRequest(actualURL));
|
||||
connect(reply, &QNetworkReply::finished, this, &BillboardOverlay::replyFinished);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,12 +33,13 @@ private slots:
|
|||
void replyFinished();
|
||||
|
||||
private:
|
||||
void setBillboardURL(const QUrl url);
|
||||
void setBillboardURL(const QString& url);
|
||||
|
||||
QUrl _url;
|
||||
QString _url;
|
||||
QByteArray _billboard;
|
||||
QSize _size;
|
||||
QScopedPointer<Texture> _billboardTexture;
|
||||
bool _newTextureNeeded;
|
||||
|
||||
QRect _fromImage; // where from in the image to sample
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <QGLWidget>
|
||||
#include <SharedUtil.h>
|
||||
#include <StreamUtils.h>
|
||||
|
||||
#include "Circle3DOverlay.h"
|
||||
#include "renderer/GlowEffect.h"
|
||||
|
@ -39,13 +40,18 @@ void Circle3DOverlay::render() {
|
|||
if (!_visible) {
|
||||
return; // do nothing if we're not visible
|
||||
}
|
||||
|
||||
float alpha = getAlpha();
|
||||
|
||||
if (alpha == 0.0) {
|
||||
return; // do nothing if our alpha is 0, we're not visible
|
||||
}
|
||||
|
||||
const float FULL_CIRCLE = 360.0f;
|
||||
const float SLICES = 180.0f; // The amount of segment to create the circle
|
||||
const float SLICE_ANGLE = FULL_CIRCLE / SLICES;
|
||||
|
||||
//const int slices = 15;
|
||||
float alpha = getAlpha();
|
||||
xColor color = getColor();
|
||||
const float MAX_COLOR = 255.0f;
|
||||
glColor4f(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
|
||||
|
@ -291,6 +297,25 @@ void Circle3DOverlay::setProperties(const QScriptValue &properties) {
|
|||
}
|
||||
}
|
||||
|
||||
bool Circle3DOverlay::findRayIntersection(const glm::vec3& origin,
|
||||
const glm::vec3& direction, float& distance, BoxFace& face) const {
|
||||
|
||||
bool intersects = Planar3DOverlay::findRayIntersection(origin, direction, distance, face);
|
||||
if (intersects) {
|
||||
glm::vec3 hitAt = origin + (direction * distance);
|
||||
float distanceToHit = glm::distance(hitAt, _position);
|
||||
|
||||
float maxDimension = glm::max(_dimensions.x, _dimensions.y);
|
||||
float innerRadius = maxDimension * getInnerRadius();
|
||||
float outerRadius = maxDimension * getOuterRadius();
|
||||
|
||||
// TODO: this really only works for circles, we should be handling the ellipse case as well...
|
||||
if (distanceToHit < innerRadius || distanceToHit > outerRadius) {
|
||||
intersects = false;
|
||||
}
|
||||
}
|
||||
return intersects;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -45,6 +45,8 @@ public:
|
|||
void setMinorTickMarksLength(float value) { _minorTickMarksLength = value; }
|
||||
void setMajorTickMarksColor(const xColor& value) { _majorTickMarksColor = value; }
|
||||
void setMinorTickMarksColor(const xColor& value) { _minorTickMarksColor = value; }
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const;
|
||||
|
||||
protected:
|
||||
float _startAt;
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <QGLWidget>
|
||||
#include <PlaneShape.h>
|
||||
#include <RayIntersectionInfo.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <StreamUtils.h>
|
||||
|
||||
|
@ -74,3 +76,29 @@ void Planar3DOverlay::setProperties(const QScriptValue& properties) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Planar3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face) const {
|
||||
|
||||
RayIntersectionInfo rayInfo;
|
||||
rayInfo._rayStart = origin;
|
||||
rayInfo._rayDirection = direction;
|
||||
rayInfo._rayLength = std::numeric_limits<float>::max();
|
||||
|
||||
PlaneShape plane;
|
||||
|
||||
const glm::vec3 UNROTATED_NORMAL(0.0f, 0.0f, -1.0f);
|
||||
glm::vec3 normal = _rotation * UNROTATED_NORMAL;
|
||||
plane.setNormal(normal);
|
||||
plane.setPoint(_position); // the position is definitely a point on our plane
|
||||
|
||||
bool intersects = plane.findRayIntersection(rayInfo);
|
||||
|
||||
if (intersects) {
|
||||
distance = rayInfo._hitDistance;
|
||||
// TODO: if it intersects, we want to check to see if the intersection point is within our dimensions
|
||||
// glm::vec3 hitAt = origin + direction * distance;
|
||||
// _dimensions
|
||||
}
|
||||
return intersects;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,8 @@ public:
|
|||
|
||||
virtual void setProperties(const QScriptValue& properties);
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const;
|
||||
|
||||
protected:
|
||||
glm::vec2 _dimensions;
|
||||
};
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <glm/gtx/vector_angle.hpp>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include "Vec3.h"
|
||||
|
@ -37,7 +39,7 @@ glm::vec3 Vec3::sum(const glm::vec3& v1, const glm::vec3& v2) {
|
|||
return v1 + v2;
|
||||
}
|
||||
glm::vec3 Vec3::subtract(const glm::vec3& v1, const glm::vec3& v2) {
|
||||
return v1 - v2;
|
||||
return v1 - v2;
|
||||
}
|
||||
|
||||
float Vec3::length(const glm::vec3& v) {
|
||||
|
@ -48,6 +50,10 @@ float Vec3::distance(const glm::vec3& v1, const glm::vec3& v2) {
|
|||
return glm::distance(v1, v2);
|
||||
}
|
||||
|
||||
float Vec3::orientedAngle(const glm::vec3& v1, const glm::vec3& v2, const glm::vec3& v3) {
|
||||
return glm::degrees(glm::orientedAngle(glm::normalize(v1), glm::normalize(v2), glm::normalize(v3)));
|
||||
}
|
||||
|
||||
glm::vec3 Vec3::normalize(const glm::vec3& v) {
|
||||
return glm::normalize(v);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ public slots:
|
|||
glm::vec3 subtract(const glm::vec3& v1, const glm::vec3& v2);
|
||||
float length(const glm::vec3& v);
|
||||
float distance(const glm::vec3& v1, const glm::vec3& v2);
|
||||
float orientedAngle(const glm::vec3& v1, const glm::vec3& v2, const glm::vec3& v3);
|
||||
glm::vec3 normalize(const glm::vec3& v);
|
||||
void print(const QString& lable, const glm::vec3& v);
|
||||
bool equal(const glm::vec3& v1, const glm::vec3& v2);
|
||||
|
|
Loading…
Reference in a new issue