mirror of
https://github.com/overte-org/overte.git
synced 2025-08-13 09:19:51 +02:00
Merge branch 'master' of https://github.com/worklist/hifi
This commit is contained in:
commit
a03716a152
19 changed files with 321 additions and 153 deletions
|
@ -9,6 +9,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var windowDimensions = Controller.getViewportDimensions();
|
||||
|
||||
var LASER_WIDTH = 4;
|
||||
var LASER_COLOR = { red: 255, green: 0, blue: 0 };
|
||||
var LASER_LENGTH_FACTOR = 1.5;
|
||||
|
@ -16,6 +18,40 @@ var LASER_LENGTH_FACTOR = 1.5;
|
|||
var LEFT = 0;
|
||||
var RIGHT = 1;
|
||||
|
||||
|
||||
var SPAWN_DISTANCE = 1;
|
||||
var radiusDefault = 0.10;
|
||||
|
||||
var modelURLs = [
|
||||
"http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/Feisar_Ship.FBX",
|
||||
"http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/birarda/birarda_head.fbx",
|
||||
"http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/pug.fbx",
|
||||
"http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/newInvader16x16-large-purple.svo",
|
||||
"http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/minotaur/mino_full.fbx",
|
||||
"http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/Combat_tank_V01.FBX",
|
||||
"http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/orc.fbx",
|
||||
"http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/slimer.fbx",
|
||||
];
|
||||
|
||||
var toolIconUrl = "http://highfidelity-public.s3-us-west-1.amazonaws.com/images/tools/";
|
||||
var numberOfTools = 1;
|
||||
var toolHeight = 50;
|
||||
var toolWidth = 50;
|
||||
var toolVerticalSpacing = 4;
|
||||
var toolsHeight = toolHeight * numberOfTools + toolVerticalSpacing * (numberOfTools - 1);
|
||||
var toolsX = windowDimensions.x - 8 - toolWidth;
|
||||
var toolsY = (windowDimensions.y - toolsHeight) / 2;
|
||||
|
||||
|
||||
var firstModel = Overlays.addOverlay("image", {
|
||||
x: 0, y: 0, width: toolWidth, height: toolHeight,
|
||||
subImage: { x: 0, y: toolHeight, width: toolWidth, height: toolHeight },
|
||||
imageURL: toolIconUrl + "voxel-tool.svg",
|
||||
x: toolsX, y: toolsY + ((toolHeight + toolVerticalSpacing) * 0), width: toolWidth, height: toolHeight,
|
||||
visible: true,
|
||||
alpha: 0.9
|
||||
});
|
||||
|
||||
function controller(wichSide) {
|
||||
this.side = wichSide;
|
||||
this.palm = 2 * wichSide;
|
||||
|
@ -46,7 +82,10 @@ function controller(wichSide) {
|
|||
this.pressing = false; // is trigger being pressed (is pressed now but wasn't previously)
|
||||
|
||||
this.grabbing = false;
|
||||
this.modelID;
|
||||
this.modelID = { isKnownID: false };
|
||||
this.oldModelRotation;
|
||||
this.oldModelPosition;
|
||||
this.oldModelRadius;
|
||||
|
||||
this.laser = Overlays.addOverlay("line3d", {
|
||||
position: this.palmPosition,
|
||||
|
@ -85,23 +124,19 @@ function controller(wichSide) {
|
|||
|
||||
|
||||
|
||||
this.grab = function (modelID) {
|
||||
if (!modelID.isKnownID) {
|
||||
var identify = Models.identifyModel(modelID);
|
||||
if (!identify.isKnownID) {
|
||||
print("Unknown ID " + identify.id + "(grab)");
|
||||
return;
|
||||
}
|
||||
modelID = identify;
|
||||
}
|
||||
this.grab = function (modelID, properties) {
|
||||
print("Grabbing " + modelID.id);
|
||||
this.grabbing = true;
|
||||
this.modelID = modelID;
|
||||
|
||||
this.oldModelPosition = properties.position;
|
||||
this.oldModelRotation = properties.modelRotation;
|
||||
this.oldModelRadius = properties.radius;
|
||||
}
|
||||
|
||||
this.release = function () {
|
||||
this.grabbing = false;
|
||||
this.modelID = 0;
|
||||
this.modelID.isKnownID = false;
|
||||
}
|
||||
|
||||
this.checkTrigger = function () {
|
||||
|
@ -118,6 +153,34 @@ function controller(wichSide) {
|
|||
}
|
||||
}
|
||||
|
||||
this.checkModel = function (properties) {
|
||||
// P P - Model
|
||||
// /| A - Palm
|
||||
// / | d B - unit vector toward tip
|
||||
// / | X - base of the perpendicular line
|
||||
// A---X----->B d - distance fom axis
|
||||
// x x - distance from A
|
||||
//
|
||||
// |X-A| = (P-A).B
|
||||
// X == A + ((P-A).B)B
|
||||
// d = |P-X|
|
||||
|
||||
var A = this.palmPosition;
|
||||
var B = this.front;
|
||||
var P = properties.position;
|
||||
|
||||
var x = Vec3.dot(Vec3.subtract(P, A), B);
|
||||
var y = Vec3.dot(Vec3.subtract(P, A), this.up);
|
||||
var z = Vec3.dot(Vec3.subtract(P, A), this.right);
|
||||
var X = Vec3.sum(A, Vec3.multiply(B, x));
|
||||
var d = Vec3.length(Vec3.subtract(P, X));
|
||||
|
||||
if (d < properties.radius && 0 < x && x < LASER_LENGTH_FACTOR) {
|
||||
return { valid: true, x: x, y: y, z: z };
|
||||
}
|
||||
return { valid: false };
|
||||
}
|
||||
|
||||
this.moveLaser = function () {
|
||||
var endPosition = Vec3.sum(this.palmPosition, Vec3.multiply(this.front, LASER_LENGTH_FACTOR));
|
||||
|
||||
|
@ -143,44 +206,33 @@ function controller(wichSide) {
|
|||
});
|
||||
}
|
||||
|
||||
this.checkModel = function (modelID) {
|
||||
if (!modelID.isKnownID) {
|
||||
var identify = Models.identifyModel(modelID);
|
||||
if (!identify.isKnownID) {
|
||||
print("Unknown ID " + identify.id + "(checkModel)");
|
||||
return;
|
||||
}
|
||||
modelID = identify;
|
||||
this.moveModel = function () {
|
||||
if (this.grabbing) {
|
||||
var newPosition = Vec3.sum(this.palmPosition,
|
||||
Vec3.multiply(this.front, this.x));
|
||||
newPosition = Vec3.sum(newPosition,
|
||||
Vec3.multiply(this.up, this.y));
|
||||
newPosition = Vec3.sum(newPosition,
|
||||
Vec3.multiply(this.right, this.z));
|
||||
|
||||
var newRotation = Quat.multiply(this.rotation,
|
||||
Quat.inverse(this.oldRotation));
|
||||
newRotation = Quat.multiply(newRotation,
|
||||
this.oldModelRotation);
|
||||
|
||||
Models.editModel(this.modelID, {
|
||||
position: newPosition,
|
||||
modelRotation: newRotation
|
||||
});
|
||||
print("Moving " + this.modelID.id);
|
||||
// Vec3.print("Old Position: ", this.oldModelPosition);
|
||||
// Vec3.print("Sav Position: ", newPosition);
|
||||
Quat.print("Old Rotation: ", this.oldModelRotation);
|
||||
Quat.print("New Rotation: ", newRotation);
|
||||
|
||||
this.oldModelRotation = newRotation;
|
||||
this.oldModelPosition = newPosition;
|
||||
}
|
||||
// P P - Model
|
||||
// /| A - Palm
|
||||
// / | d B - unit vector toward tip
|
||||
// / | X - base of the perpendicular line
|
||||
// A---X----->B d - distance fom axis
|
||||
// x x - distance from A
|
||||
//
|
||||
// |X-A| = (P-A).B
|
||||
// X == A + ((P-A).B)B
|
||||
// d = |P-X|
|
||||
|
||||
var A = this.palmPosition;
|
||||
var B = this.front;
|
||||
var P = Models.getModelProperties(modelID).position;
|
||||
|
||||
this.x = Vec3.dot(Vec3.subtract(P, A), B);
|
||||
this.y = Vec3.dot(Vec3.subtract(P, A), this.up);
|
||||
this.z = Vec3.dot(Vec3.subtract(P, A), this.right);
|
||||
var X = Vec3.sum(A, Vec3.multiply(B, this.x));
|
||||
var d = Vec3.length(Vec3.subtract(P, X));
|
||||
|
||||
// Vec3.print("A: ", A);
|
||||
// Vec3.print("B: ", B);
|
||||
// Vec3.print("Particle pos: ", P);
|
||||
// print("d: " + d + ", x: " + this.x);
|
||||
if (d < Models.getModelProperties(modelID).radius && 0 < this.x && this.x < LASER_LENGTH_FACTOR) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
this.update = function () {
|
||||
|
@ -205,25 +257,40 @@ function controller(wichSide) {
|
|||
|
||||
this.checkTrigger();
|
||||
|
||||
if (this.pressing) {
|
||||
Vec3.print("Looking at: ", this.palmPosition);
|
||||
var foundModels = Models.findModels(this.palmPosition, LASER_LENGTH_FACTOR);
|
||||
for (var i = 0; i < foundModels.length; i++) {
|
||||
print("Model found ID (" + foundModels[i].id + ")");
|
||||
if (this.checkModel(foundModels[i])) {
|
||||
if (this.grab(foundModels[i])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.moveLaser();
|
||||
|
||||
if (!this.pressed && this.grabbing) {
|
||||
// release if trigger not pressed anymore.
|
||||
this.release();
|
||||
}
|
||||
|
||||
this.moveLaser();
|
||||
|
||||
if (this.pressing) {
|
||||
Vec3.print("Looking at: ", this.palmPosition);
|
||||
var foundModels = Models.findModels(this.palmPosition, LASER_LENGTH_FACTOR);
|
||||
for (var i = 0; i < foundModels.length; i++) {
|
||||
|
||||
if (!foundModels[i].isKnownID) {
|
||||
var identify = Models.identifyModel(foundModels[i]);
|
||||
if (!identify.isKnownID) {
|
||||
print("Unknown ID " + identify.id + "(update loop)");
|
||||
return;
|
||||
}
|
||||
foundModels[i] = identify;
|
||||
}
|
||||
|
||||
var properties = Models.getModelProperties(foundModels[i]);
|
||||
print("Checking properties: " + properties.id + " " + properties.isKnownID);
|
||||
|
||||
var check = this.checkModel(properties);
|
||||
if (check.valid) {
|
||||
this.grab(foundModels[i], properties);
|
||||
this.x = check.x;
|
||||
this.y = check.y;
|
||||
this.z = check.z;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.cleanup = function () {
|
||||
|
@ -238,78 +305,44 @@ var leftController = new controller(LEFT);
|
|||
var rightController = new controller(RIGHT);
|
||||
|
||||
function moveModels() {
|
||||
if (leftController.grabbing) {
|
||||
if (rightController.grabbing) {
|
||||
var properties = Models.getModelProperties(leftController.modelID);
|
||||
|
||||
var oldLeftPoint = Vec3.sum(leftController.oldPalmPosition, Vec3.multiply(leftController.oldFront, leftController.x));
|
||||
var oldRightPoint = Vec3.sum(rightController.oldPalmPosition, Vec3.multiply(rightController.oldFront, rightController.x));
|
||||
|
||||
var oldMiddle = Vec3.multiply(Vec3.sum(oldLeftPoint, oldRightPoint), 0.5);
|
||||
var oldLength = Vec3.length(Vec3.subtract(oldLeftPoint, oldRightPoint));
|
||||
|
||||
|
||||
var leftPoint = Vec3.sum(leftController.palmPosition, Vec3.multiply(leftController.front, leftController.x));
|
||||
var rightPoint = Vec3.sum(rightController.palmPosition, Vec3.multiply(rightController.front, rightController.x));
|
||||
|
||||
var middle = Vec3.multiply(Vec3.sum(leftPoint, rightPoint), 0.5);
|
||||
var length = Vec3.length(Vec3.subtract(leftPoint, rightPoint));
|
||||
|
||||
var ratio = length / oldLength;
|
||||
|
||||
var newPosition = Vec3.sum(middle,
|
||||
Vec3.multiply(Vec3.subtract(properties.position, oldMiddle), ratio));
|
||||
Vec3.print("Ratio : " + ratio + " New position: ", newPosition);
|
||||
var rotation = Quat.multiply(leftController.rotation,
|
||||
Quat.inverse(leftController.oldRotation));
|
||||
rotation = Quat.multiply(rotation, properties.modelRotation);
|
||||
|
||||
Models.editModel(leftController.modelID, {
|
||||
position: newPosition,
|
||||
//modelRotation: rotation,
|
||||
radius: properties.radius * ratio
|
||||
});
|
||||
|
||||
return;
|
||||
} else {
|
||||
var newPosition = Vec3.sum(leftController.palmPosition,
|
||||
Vec3.multiply(leftController.front, leftController.x));
|
||||
newPosition = Vec3.sum(newPosition,
|
||||
Vec3.multiply(leftController.up, leftController.y));
|
||||
newPosition = Vec3.sum(newPosition,
|
||||
Vec3.multiply(leftController.right, leftController.z));
|
||||
|
||||
var rotation = Quat.multiply(leftController.rotation,
|
||||
Quat.inverse(leftController.oldRotation));
|
||||
rotation = Quat.multiply(rotation,
|
||||
Models.getModelProperties(leftController.modelID).modelRotation);
|
||||
|
||||
Models.editModel(leftController.modelID, {
|
||||
position: newPosition,
|
||||
modelRotation: rotation
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (rightController.grabbing) {
|
||||
var newPosition = Vec3.sum(rightController.palmPosition,
|
||||
Vec3.multiply(rightController.front, rightController.x));
|
||||
newPosition = Vec3.sum(newPosition,
|
||||
Vec3.multiply(rightController.up, rightController.y));
|
||||
newPosition = Vec3.sum(newPosition,
|
||||
Vec3.multiply(rightController.right, rightController.z));
|
||||
if (leftController.grabbing && rightController.grabbing && rightController.modelID.id == leftController.modelID.id) {
|
||||
print("Both controllers");
|
||||
var oldLeftPoint = Vec3.sum(leftController.oldPalmPosition, Vec3.multiply(leftController.oldFront, leftController.x));
|
||||
var oldRightPoint = Vec3.sum(rightController.oldPalmPosition, Vec3.multiply(rightController.oldFront, rightController.x));
|
||||
|
||||
var rotation = Quat.multiply(rightController.rotation,
|
||||
Quat.inverse(rightController.oldRotation));
|
||||
rotation = Quat.multiply(rotation,
|
||||
Models.getModelProperties(rightController.modelID).modelRotation);
|
||||
var oldMiddle = Vec3.multiply(Vec3.sum(oldLeftPoint, oldRightPoint), 0.5);
|
||||
var oldLength = Vec3.length(Vec3.subtract(oldLeftPoint, oldRightPoint));
|
||||
|
||||
Models.editModel(rightController.modelID, {
|
||||
|
||||
var leftPoint = Vec3.sum(leftController.palmPosition, Vec3.multiply(leftController.front, leftController.x));
|
||||
var rightPoint = Vec3.sum(rightController.palmPosition, Vec3.multiply(rightController.front, rightController.x));
|
||||
|
||||
var middle = Vec3.multiply(Vec3.sum(leftPoint, rightPoint), 0.5);
|
||||
var length = Vec3.length(Vec3.subtract(leftPoint, rightPoint));
|
||||
|
||||
var ratio = length / oldLength;
|
||||
|
||||
var newPosition = Vec3.sum(middle,
|
||||
Vec3.multiply(Vec3.subtract(leftController.oldModelPosition, oldMiddle), ratio));
|
||||
Vec3.print("Ratio : " + ratio + " New position: ", newPosition);
|
||||
var rotation = Quat.multiply(leftController.rotation,
|
||||
Quat.inverse(leftController.oldRotation));
|
||||
rotation = Quat.multiply(rotation, leftController.oldModelRotation);
|
||||
|
||||
Models.editModel(leftController.modelID, {
|
||||
position: newPosition,
|
||||
modelRotation: rotation
|
||||
//modelRotation: rotation,
|
||||
radius: leftController.oldModelRadius * ratio
|
||||
});
|
||||
|
||||
leftController.oldModelPosition = newPosition;
|
||||
leftController.oldModelRotation = rotation;
|
||||
leftController.oldModelRadius *= ratio;
|
||||
return;
|
||||
}
|
||||
|
||||
leftController.moveModel();
|
||||
rightController.moveModel();
|
||||
}
|
||||
|
||||
function checkController(deltaTime) {
|
||||
|
@ -318,6 +351,8 @@ function checkController(deltaTime) {
|
|||
var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
|
||||
var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
|
||||
|
||||
moveOverlays();
|
||||
|
||||
// this is expected for hydras
|
||||
if (!(numberOfButtons==12 && numberOfTriggers == 2 && controllersPerTrigger == 2)) {
|
||||
//print("no hydra connected?");
|
||||
|
@ -329,14 +364,48 @@ function checkController(deltaTime) {
|
|||
moveModels();
|
||||
}
|
||||
|
||||
function moveOverlays() {
|
||||
windowDimensions = Controller.getViewportDimensions();
|
||||
|
||||
toolsX = windowDimensions.x - 8 - toolWidth;
|
||||
toolsY = (windowDimensions.y - toolsHeight) / 2;
|
||||
|
||||
Overlays.addOverlay(firstModel, {
|
||||
x: toolsX, y: toolsY + ((toolHeight + toolVerticalSpacing) * 0), width: toolWidth, height: toolHeight,
|
||||
});
|
||||
}
|
||||
|
||||
function mousePressEvent(event) {
|
||||
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
|
||||
var url;
|
||||
|
||||
if (clickedOverlay == firstModel) {
|
||||
url = Window.prompt("Model url", modelURLs[Math.floor(Math.random() * modelURLs.length)]);
|
||||
if (url == null) {
|
||||
return; }
|
||||
} else {
|
||||
print("Didn't click on anything");
|
||||
return;
|
||||
}
|
||||
|
||||
var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE));
|
||||
Models.addModel({ position: position,
|
||||
radius: radiusDefault,
|
||||
modelURL: url
|
||||
});
|
||||
}
|
||||
|
||||
function scriptEnding() {
|
||||
leftController.cleanup();
|
||||
rightController.cleanup();
|
||||
|
||||
Overlays.deleteOverlay(firstModel);
|
||||
}
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
||||
// register the call back so it fires before each data send
|
||||
Script.update.connect(checkController);
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
|
||||
|
||||
|
||||
|
|
BIN
interface/resources/sounds/mention/Mentioned A.wav
Normal file
BIN
interface/resources/sounds/mention/Mentioned A.wav
Normal file
Binary file not shown.
BIN
interface/resources/sounds/mention/Mentioned B.wav
Normal file
BIN
interface/resources/sounds/mention/Mentioned B.wav
Normal file
Binary file not shown.
BIN
interface/resources/sounds/mention/Mentioned C.wav
Normal file
BIN
interface/resources/sounds/mention/Mentioned C.wav
Normal file
Binary file not shown.
|
@ -2843,7 +2843,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
|
|||
// save absolute translations
|
||||
glm::vec3 absoluteSkeletonTranslation = _myAvatar->getSkeletonModel().getTranslation();
|
||||
glm::vec3 absoluteFaceTranslation = _myAvatar->getHead()->getFaceModel().getTranslation();
|
||||
|
||||
|
||||
// get the eye positions relative to the neck and use them to set the face translation
|
||||
glm::vec3 leftEyePosition, rightEyePosition;
|
||||
_myAvatar->getHead()->getFaceModel().setTranslation(glm::vec3());
|
||||
|
@ -2857,11 +2857,22 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
|
|||
_myAvatar->getSkeletonModel().setTranslation(_myAvatar->getHead()->getFaceModel().getTranslation() -
|
||||
neckPosition);
|
||||
|
||||
// update the attachments to match
|
||||
QVector<glm::vec3> absoluteAttachmentTranslations;
|
||||
glm::vec3 delta = _myAvatar->getSkeletonModel().getTranslation() - absoluteSkeletonTranslation;
|
||||
foreach (Model* attachment, _myAvatar->getAttachmentModels()) {
|
||||
absoluteAttachmentTranslations.append(attachment->getTranslation());
|
||||
attachment->setTranslation(attachment->getTranslation() + delta);
|
||||
}
|
||||
|
||||
displaySide(_mirrorCamera, true);
|
||||
|
||||
// restore absolute translations
|
||||
_myAvatar->getSkeletonModel().setTranslation(absoluteSkeletonTranslation);
|
||||
_myAvatar->getHead()->getFaceModel().setTranslation(absoluteFaceTranslation);
|
||||
for (int i = 0; i < absoluteAttachmentTranslations.size(); i++) {
|
||||
_myAvatar->getAttachmentModels().at(i)->setTranslation(absoluteAttachmentTranslations.at(i));
|
||||
}
|
||||
} else {
|
||||
displaySide(_mirrorCamera, true);
|
||||
}
|
||||
|
|
|
@ -215,6 +215,10 @@ Menu::Menu() :
|
|||
toggleChat();
|
||||
connect(&xmppClient, SIGNAL(connected()), this, SLOT(toggleChat()));
|
||||
connect(&xmppClient, SIGNAL(disconnected()), this, SLOT(toggleChat()));
|
||||
|
||||
QDir::setCurrent(Application::resourcesPath());
|
||||
// init chat window to listen chat
|
||||
_chatWindow = new ChatWindow(Application::getInstance()->getWindow());
|
||||
#endif
|
||||
|
||||
QMenu* viewMenu = addMenu("View");
|
||||
|
|
|
@ -424,19 +424,24 @@ void ModelUploader::processCheck() {
|
|||
}
|
||||
|
||||
bool ModelUploader::addTextures(const QString& texdir, const FBXGeometry& geometry) {
|
||||
QSet<QByteArray> added;
|
||||
foreach (FBXMesh mesh, geometry.meshes) {
|
||||
foreach (FBXMeshPart part, mesh.parts) {
|
||||
if (!part.diffuseTexture.filename.isEmpty() && part.diffuseTexture.content.isEmpty()) {
|
||||
if (!part.diffuseTexture.filename.isEmpty() && part.diffuseTexture.content.isEmpty() &&
|
||||
!added.contains(part.diffuseTexture.filename)) {
|
||||
if (!addPart(texdir + "/" + part.diffuseTexture.filename,
|
||||
QString("texture%1").arg(++_texturesCount), true)) {
|
||||
return false;
|
||||
}
|
||||
added.insert(part.diffuseTexture.filename);
|
||||
}
|
||||
if (!part.normalTexture.filename.isEmpty() && part.normalTexture.content.isEmpty()) {
|
||||
if (!part.normalTexture.filename.isEmpty() && part.normalTexture.content.isEmpty() &&
|
||||
!added.contains(part.normalTexture.filename)) {
|
||||
if (!addPart(texdir + "/" + part.normalTexture.filename,
|
||||
QString("texture%1").arg(++_texturesCount), true)) {
|
||||
return false;
|
||||
}
|
||||
added.insert(part.normalTexture.filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ void XmppClient::xmppConnected() {
|
|||
_publicChatRoom = _xmppMUCManager.addRoom(DEFAULT_CHAT_ROOM);
|
||||
_publicChatRoom->setNickName(AccountManager::getInstance().getAccountInfo().getUsername());
|
||||
_publicChatRoom->join();
|
||||
emit joinedPublicChatRoom();
|
||||
}
|
||||
|
||||
void XmppClient::xmppError(QXmppClient::Error error) {
|
||||
|
|
|
@ -28,6 +28,9 @@ public:
|
|||
QXmppClient& getXMPPClient() { return _xmppClient; }
|
||||
const QXmppMucRoom* getPublicChatRoom() const { return _publicChatRoom; }
|
||||
|
||||
signals:
|
||||
void joinedPublicChatRoom();
|
||||
|
||||
private slots:
|
||||
void xmppConnected();
|
||||
void xmppError(QXmppClient::Error error);
|
||||
|
|
|
@ -369,7 +369,7 @@ void Avatar::simulateAttachments(float deltaTime) {
|
|||
glm::quat jointRotation;
|
||||
if (_skeletonModel.getJointPosition(jointIndex, jointPosition) &&
|
||||
_skeletonModel.getJointRotation(jointIndex, jointRotation)) {
|
||||
model->setTranslation(jointPosition + jointRotation * attachment.translation * _skeletonModel.getScale());
|
||||
model->setTranslation(jointPosition + jointRotation * attachment.translation * _scale);
|
||||
model->setRotation(jointRotation * attachment.rotation);
|
||||
model->setScale(_skeletonModel.getScale() * attachment.scale);
|
||||
model->simulate(deltaTime);
|
||||
|
|
|
@ -83,6 +83,7 @@ public:
|
|||
//getters
|
||||
bool isInitialized() const { return _initialized; }
|
||||
SkeletonModel& getSkeletonModel() { return _skeletonModel; }
|
||||
const QVector<Model*>& getAttachmentModels() const { return _attachmentModels; }
|
||||
glm::vec3 getChestPosition() const;
|
||||
float getScale() const { return _scale; }
|
||||
const glm::vec3& getVelocity() const { return _velocity; }
|
||||
|
|
|
@ -220,15 +220,10 @@ void FaceplusReader::update() {
|
|||
if (!_referenceInitialized) {
|
||||
_referenceX = x;
|
||||
_referenceY = y;
|
||||
_referenceScale = scale;
|
||||
_referenceInitialized = true;
|
||||
}
|
||||
const float TRANSLATION_SCALE = 10.0f;
|
||||
const float REFERENCE_DISTANCE = 10.0f;
|
||||
float depthScale = _referenceScale / scale;
|
||||
float z = REFERENCE_DISTANCE * (depthScale - 1.0f);
|
||||
glm::vec3 headTranslation((x - _referenceX) * depthScale * TRANSLATION_SCALE,
|
||||
(y - _referenceY) * depthScale * TRANSLATION_SCALE, z);
|
||||
glm::vec3 headTranslation((x - _referenceX) * TRANSLATION_SCALE, (y - _referenceY) * TRANSLATION_SCALE, 0.0f);
|
||||
glm::quat headRotation(glm::radians(glm::vec3(-_outputVector.at(_headRotationIndices[0]),
|
||||
_outputVector.at(_headRotationIndices[1]), -_outputVector.at(_headRotationIndices[2]))));
|
||||
float estimatedEyePitch = (_outputVector.at(_leftEyeRotationIndices[0]) +
|
||||
|
|
|
@ -76,7 +76,6 @@ private:
|
|||
int _rightEyeRotationIndices[2];
|
||||
float _referenceX;
|
||||
float _referenceY;
|
||||
float _referenceScale;
|
||||
bool _referenceInitialized;
|
||||
QVector<float> _blendshapeCoefficients;
|
||||
#endif
|
||||
|
|
|
@ -37,6 +37,7 @@ AttachmentsDialog::AttachmentsDialog() :
|
|||
container->setLayout(_attachments = new QVBoxLayout());
|
||||
container->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred);
|
||||
area->setWidget(container);
|
||||
_attachments->addStretch(1);
|
||||
|
||||
foreach (const AttachmentData& data, Application::getInstance()->getAvatar()->getAttachmentData()) {
|
||||
addAttachment(data);
|
||||
|
@ -49,20 +50,30 @@ AttachmentsDialog::AttachmentsDialog() :
|
|||
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok);
|
||||
layout->addWidget(buttons);
|
||||
connect(buttons, SIGNAL(accepted()), SLOT(deleteLater()));
|
||||
_ok = buttons->button(QDialogButtonBox::Ok);
|
||||
|
||||
setMinimumSize(600, 600);
|
||||
}
|
||||
|
||||
void AttachmentsDialog::setVisible(bool visible) {
|
||||
QDialog::setVisible(visible);
|
||||
|
||||
// un-default the OK button
|
||||
if (visible) {
|
||||
_ok->setDefault(false);
|
||||
}
|
||||
}
|
||||
|
||||
void AttachmentsDialog::updateAttachmentData() {
|
||||
QVector<AttachmentData> data;
|
||||
for (int i = 0; i < _attachments->count(); i++) {
|
||||
for (int i = 0; i < _attachments->count() - 1; i++) {
|
||||
data.append(static_cast<AttachmentPanel*>(_attachments->itemAt(i)->widget())->getAttachmentData());
|
||||
}
|
||||
Application::getInstance()->getAvatar()->setAttachmentData(data);
|
||||
}
|
||||
|
||||
void AttachmentsDialog::addAttachment(const AttachmentData& data) {
|
||||
_attachments->addWidget(new AttachmentPanel(this, data));
|
||||
_attachments->insertWidget(_attachments->count() - 1, new AttachmentPanel(this, data));
|
||||
}
|
||||
|
||||
static QDoubleSpinBox* createTranslationBox(AttachmentsDialog* dialog, float value) {
|
||||
|
@ -86,7 +97,10 @@ static QDoubleSpinBox* createRotationBox(AttachmentsDialog* dialog, float value)
|
|||
}
|
||||
|
||||
AttachmentPanel::AttachmentPanel(AttachmentsDialog* dialog, const AttachmentData& data) {
|
||||
setFrameStyle(QFrame::StyledPanel);
|
||||
|
||||
QFormLayout* layout = new QFormLayout();
|
||||
layout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
|
||||
setLayout(layout);
|
||||
|
||||
QHBoxLayout* urlBox = new QHBoxLayout();
|
||||
|
@ -130,6 +144,7 @@ AttachmentPanel::AttachmentPanel(AttachmentsDialog* dialog, const AttachmentData
|
|||
QPushButton* remove = new QPushButton("Delete");
|
||||
layout->addRow(remove);
|
||||
connect(remove, SIGNAL(clicked(bool)), SLOT(deleteLater()));
|
||||
dialog->connect(remove, SIGNAL(clicked(bool)), SLOT(updateAttachmentData()), Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
AttachmentData AttachmentPanel::getAttachmentData() const {
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define hifi_AttachmentsDialog_h
|
||||
|
||||
#include <QDialog>
|
||||
#include <QFrame>
|
||||
|
||||
#include <AvatarData.h>
|
||||
|
||||
|
@ -29,6 +30,8 @@ public:
|
|||
|
||||
AttachmentsDialog();
|
||||
|
||||
virtual void setVisible(bool visible);
|
||||
|
||||
public slots:
|
||||
|
||||
void updateAttachmentData();
|
||||
|
@ -40,10 +43,11 @@ private slots:
|
|||
private:
|
||||
|
||||
QVBoxLayout* _attachments;
|
||||
QPushButton* _ok;
|
||||
};
|
||||
|
||||
/// A panel controlling a single attachment.
|
||||
class AttachmentPanel : public QWidget {
|
||||
class AttachmentPanel : public QFrame {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
|
|
@ -26,17 +26,23 @@
|
|||
|
||||
#include "ChatWindow.h"
|
||||
|
||||
|
||||
|
||||
const int NUM_MESSAGES_TO_TIME_STAMP = 20;
|
||||
|
||||
const QRegularExpression regexLinks("((?:(?:ftp)|(?:https?))://\\S+)");
|
||||
const QRegularExpression regexHifiLinks("([#@]\\S+)");
|
||||
const QString mentionSoundsPath("/sounds/mention/");
|
||||
const QString mentionRegex("@(\\b%1\\b)");
|
||||
|
||||
ChatWindow::ChatWindow(QWidget* parent) :
|
||||
FramelessDialog(parent, 0, POSITION_RIGHT),
|
||||
ui(new Ui::ChatWindow),
|
||||
numMessagesAfterLastTimeStamp(0),
|
||||
_mousePressed(false),
|
||||
_mouseStartPosition()
|
||||
_mouseStartPosition(),
|
||||
_trayIcon(parent),
|
||||
_effectPlayer()
|
||||
{
|
||||
setAttribute(Qt::WA_DeleteOnClose, false);
|
||||
|
||||
|
@ -77,16 +83,47 @@ ChatWindow::ChatWindow(QWidget* parent) :
|
|||
ui->usersWidget->hide();
|
||||
ui->messagesScrollArea->hide();
|
||||
ui->messagePlainTextEdit->hide();
|
||||
connect(&xmppClient, SIGNAL(connected()), this, SLOT(connected()));
|
||||
connect(&XmppClient::getInstance(), SIGNAL(joinedPublicChatRoom()), this, SLOT(connected()));
|
||||
}
|
||||
connect(&xmppClient, SIGNAL(messageReceived(QXmppMessage)), this, SLOT(messageReceived(QXmppMessage)));
|
||||
connect(&_trayIcon, SIGNAL(messageClicked()), this, SLOT(notificationClicked()));
|
||||
#endif
|
||||
|
||||
QDir mentionSoundsDir(Application::resourcesPath() + mentionSoundsPath);
|
||||
_mentionSounds = mentionSoundsDir.entryList(QDir::Files);
|
||||
_trayIcon.setIcon(QIcon( Application::resourcesPath() + "/images/hifi-logo.svg"));
|
||||
}
|
||||
|
||||
void ChatWindow::notificationClicked() {
|
||||
if (parentWidget()->isMinimized()) {
|
||||
parentWidget()->showNormal();
|
||||
}
|
||||
if (isHidden()) {
|
||||
show();
|
||||
}
|
||||
|
||||
// find last mention
|
||||
int messageCount = ui->messagesVBoxLayout->count();
|
||||
for (unsigned int i = messageCount; i > 0; i--) {
|
||||
ChatMessageArea* area = (ChatMessageArea*)ui->messagesVBoxLayout->itemAt(i - 1)->widget();
|
||||
QRegularExpression usernameMention(mentionRegex.arg(AccountManager::getInstance().getAccountInfo().getUsername()));
|
||||
if (area->toPlainText().contains(usernameMention)) {
|
||||
int top = area->geometry().top();
|
||||
int height = area->geometry().height();
|
||||
|
||||
QScrollBar* verticalScrollBar = ui->messagesScrollArea->verticalScrollBar();
|
||||
verticalScrollBar->setSliderPosition(top - verticalScrollBar->size().height() + height);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
scrollToBottom();
|
||||
}
|
||||
|
||||
ChatWindow::~ChatWindow() {
|
||||
#ifdef HAVE_QXMPP
|
||||
const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
|
||||
disconnect(&xmppClient, SIGNAL(connected()), this, SLOT(connected()));
|
||||
disconnect(&xmppClient, SIGNAL(joinedPublicChatRoom()), this, SLOT(connected()));
|
||||
disconnect(&xmppClient, SIGNAL(messageReceived(QXmppMessage)), this, SLOT(messageReceived(QXmppMessage)));
|
||||
|
||||
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
|
||||
|
@ -105,9 +142,15 @@ void ChatWindow::keyPressEvent(QKeyEvent* event) {
|
|||
|
||||
void ChatWindow::showEvent(QShowEvent* event) {
|
||||
FramelessDialog::showEvent(event);
|
||||
|
||||
if (!event->spontaneous()) {
|
||||
ui->messagePlainTextEdit->setFocus();
|
||||
}
|
||||
|
||||
const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
|
||||
if (xmppClient.isConnected()) {
|
||||
participantsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool ChatWindow::eventFilter(QObject* sender, QEvent* event) {
|
||||
|
@ -304,6 +347,21 @@ void ChatWindow::messageReceived(const QXmppMessage& message) {
|
|||
} else {
|
||||
lastMessageStamp = QDateTime::currentDateTime();
|
||||
}
|
||||
|
||||
QRegularExpression usernameMention(mentionRegex.arg(AccountManager::getInstance().getAccountInfo().getUsername()));
|
||||
if (isHidden() && message.body().contains(usernameMention)) {
|
||||
if (_effectPlayer.state() != QMediaPlayer::PlayingState) {
|
||||
// get random sound
|
||||
QFileInfo inf = QFileInfo(Application::resourcesPath() +
|
||||
mentionSoundsPath +
|
||||
_mentionSounds.at(rand() % _mentionSounds.size()));
|
||||
_effectPlayer.setMedia(QUrl::fromLocalFile(inf.absoluteFilePath()));
|
||||
_effectPlayer.play();
|
||||
}
|
||||
|
||||
_trayIcon.show();
|
||||
_trayIcon.showMessage(windowTitle(), message.body());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
#include <QDateTime>
|
||||
#include <QDockWidget>
|
||||
#include <QMediaPlayer>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QTimer>
|
||||
|
||||
#include <Application.h>
|
||||
|
@ -63,6 +65,9 @@ private:
|
|||
QDateTime lastMessageStamp;
|
||||
bool _mousePressed;
|
||||
QPoint _mouseStartPosition;
|
||||
QSystemTrayIcon _trayIcon;
|
||||
QStringList _mentionSounds;
|
||||
QMediaPlayer _effectPlayer;
|
||||
|
||||
private slots:
|
||||
void connected();
|
||||
|
@ -71,6 +76,7 @@ private slots:
|
|||
void error(QXmppClient::Error error);
|
||||
void participantsChanged();
|
||||
void messageReceived(const QXmppMessage& message);
|
||||
void notificationClicked();
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -198,9 +198,6 @@ color: #0e7077</string>
|
|||
<property name="indent">
|
||||
<number>25</number>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring></cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -510,7 +507,7 @@ color: #0e7077</string>
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="headLabel">
|
||||
<widget class="QLabel" name="headLabel_3">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
|
@ -547,7 +544,7 @@ color: #0e7077</string>
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_1">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="snapshotLocationEdit">
|
||||
<property name="sizePolicy">
|
||||
|
@ -564,7 +561,7 @@ color: #0e7077</string>
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<spacer name="horizontalSpacer_1">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
|
|
|
@ -46,7 +46,7 @@ const uint16_t MODEL_PACKET_CONTAINS_MODEL_ROTATION = 2048;
|
|||
const float MODEL_DEFAULT_RADIUS = 0.1f / TREE_SCALE;
|
||||
const float MINIMUM_MODEL_ELEMENT_SIZE = (1.0f / 100000.0f) / TREE_SCALE; // smallest size container
|
||||
const QString MODEL_DEFAULT_MODEL_URL("");
|
||||
const glm::quat MODEL_DEFAULT_MODEL_ROTATION(0, 0, 0, 0);
|
||||
const glm::quat MODEL_DEFAULT_MODEL_ROTATION;
|
||||
|
||||
/// A collection of properties of a model item used in the scripting API. Translates between the actual properties of a model
|
||||
/// and a JavaScript style hash/QScriptValue storing a set of properties. Used in scripting to set/get the complete set of
|
||||
|
|
Loading…
Reference in a new issue