mirror of
https://github.com/overte-org/overte.git
synced 2025-04-24 02:13:28 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi
Conflicts: interface/src/Application.cpp interface/src/Application.h
This commit is contained in:
commit
5665e4d278
20 changed files with 334 additions and 187 deletions
|
@ -188,7 +188,7 @@ function controller(wichSide) {
|
|||
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) {
|
||||
if (0 < x && x < LASER_LENGTH_FACTOR) {
|
||||
return { valid: true, x: x, y: y, z: z };
|
||||
}
|
||||
return { valid: false };
|
||||
|
@ -293,39 +293,43 @@ function controller(wichSide) {
|
|||
|
||||
if (this.pressing) {
|
||||
Vec3.print("Looking at: ", this.palmPosition);
|
||||
var foundModels = Models.findModels(this.palmPosition, LASER_LENGTH_FACTOR);
|
||||
var pickRay = { origin: this.palmPosition,
|
||||
direction: Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)) };
|
||||
var foundIntersection = Models.findRayIntersection(pickRay);
|
||||
|
||||
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;
|
||||
if(!foundIntersection.accurate) {
|
||||
return;
|
||||
}
|
||||
var foundModel = foundIntersection.modelID;
|
||||
|
||||
if (!foundModel.isKnownID) {
|
||||
var identify = Models.identifyModel(foundModel);
|
||||
if (!identify.isKnownID) {
|
||||
print("Unknown ID " + identify.id + " (update loop " + foundModel.id + ")");
|
||||
continue;
|
||||
}
|
||||
|
||||
var properties = Models.getModelProperties(foundModels[i]);
|
||||
print("foundModels["+i+"].modelURL=" + properties.modelURL);
|
||||
|
||||
if (isLocked(properties)) {
|
||||
print("Model locked " + properties.id);
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
foundModel = identify;
|
||||
}
|
||||
|
||||
var properties = Models.getModelProperties(foundModel);
|
||||
print("foundModel.modelURL=" + properties.modelURL);
|
||||
|
||||
if (isLocked(properties)) {
|
||||
print("Model locked " + properties.id);
|
||||
} else {
|
||||
print("Checking properties: " + properties.id + " " + properties.isKnownID);
|
||||
var check = this.checkModel(properties);
|
||||
if (check.valid) {
|
||||
this.grab(foundModel, properties);
|
||||
this.x = check.x;
|
||||
this.y = check.y;
|
||||
this.z = check.z;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.cleanup = function () {
|
||||
Overlays.deleteOverlay(this.laser);
|
||||
Overlays.deleteOverlay(this.ball);
|
||||
|
@ -478,93 +482,97 @@ function mousePressEvent(event) {
|
|||
} else {
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
Vec3.print("[Mouse] Looking at: ", pickRay.origin);
|
||||
var foundModels = Models.findModels(pickRay.origin, LASER_LENGTH_FACTOR);
|
||||
var closest = -1.0;
|
||||
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)");
|
||||
continue;
|
||||
}
|
||||
foundModels[i] = identify;
|
||||
}
|
||||
|
||||
var properties = Models.getModelProperties(foundModels[i]);
|
||||
if (isLocked(properties)) {
|
||||
print("Model locked " + properties.id);
|
||||
} else {
|
||||
print("Checking properties: " + properties.id + " " + properties.isKnownID);
|
||||
// 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 = pickRay.origin;
|
||||
var B = Vec3.normalize(pickRay.direction);
|
||||
var P = properties.position;
|
||||
|
||||
var x = Vec3.dot(Vec3.subtract(P, A), B);
|
||||
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) {
|
||||
if (closest < 0.0) {
|
||||
closest = x;
|
||||
}
|
||||
|
||||
if (x <= closest) {
|
||||
modelSelected = true;
|
||||
selectedModelID = foundModels[i];
|
||||
selectedModelProperties = properties;
|
||||
|
||||
orientation = MyAvatar.orientation;
|
||||
intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation));
|
||||
}
|
||||
}
|
||||
var foundIntersection = Models.findRayIntersection(pickRay);
|
||||
|
||||
if(!foundIntersection.accurate) {
|
||||
return;
|
||||
}
|
||||
var foundModel = foundIntersection.modelID;
|
||||
|
||||
if (!foundModel.isKnownID) {
|
||||
var identify = Models.identifyModel(foundModel);
|
||||
if (!identify.isKnownID) {
|
||||
print("Unknown ID " + identify.id + " (update loop " + foundModel.id + ")");
|
||||
continue;
|
||||
}
|
||||
foundModel = identify;
|
||||
}
|
||||
|
||||
if (modelSelected) {
|
||||
selectedModelProperties.oldRadius = selectedModelProperties.radius;
|
||||
selectedModelProperties.oldPosition = {
|
||||
x: selectedModelProperties.position.x,
|
||||
y: selectedModelProperties.position.y,
|
||||
z: selectedModelProperties.position.z,
|
||||
};
|
||||
selectedModelProperties.oldRotation = {
|
||||
x: selectedModelProperties.modelRotation.x,
|
||||
y: selectedModelProperties.modelRotation.y,
|
||||
z: selectedModelProperties.modelRotation.z,
|
||||
w: selectedModelProperties.modelRotation.w,
|
||||
};
|
||||
var properties = Models.getModelProperties(foundModel);
|
||||
if (isLocked(properties)) {
|
||||
print("Model locked " + properties.id);
|
||||
} else {
|
||||
print("Checking properties: " + properties.id + " " + properties.isKnownID);
|
||||
// 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|
|
||||
|
||||
selectedModelProperties.glowLevel = 0.1;
|
||||
Models.editModel(selectedModelID, { glowLevel: selectedModelProperties.glowLevel});
|
||||
var A = pickRay.origin;
|
||||
var B = Vec3.normalize(pickRay.direction);
|
||||
var P = properties.position;
|
||||
|
||||
print("Clicked on " + selectedModelID.id + " " + modelSelected);
|
||||
var x = Vec3.dot(Vec3.subtract(P, A), B);
|
||||
var X = Vec3.sum(A, Vec3.multiply(B, x));
|
||||
var d = Vec3.length(Vec3.subtract(P, X));
|
||||
|
||||
if (0 < x && x < LASER_LENGTH_FACTOR) {
|
||||
modelSelected = true;
|
||||
selectedModelID = foundModel;
|
||||
selectedModelProperties = properties;
|
||||
|
||||
orientation = MyAvatar.orientation;
|
||||
intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (modelSelected) {
|
||||
selectedModelProperties.oldRadius = selectedModelProperties.radius;
|
||||
selectedModelProperties.oldPosition = {
|
||||
x: selectedModelProperties.position.x,
|
||||
y: selectedModelProperties.position.y,
|
||||
z: selectedModelProperties.position.z,
|
||||
};
|
||||
selectedModelProperties.oldRotation = {
|
||||
x: selectedModelProperties.modelRotation.x,
|
||||
y: selectedModelProperties.modelRotation.y,
|
||||
z: selectedModelProperties.modelRotation.z,
|
||||
w: selectedModelProperties.modelRotation.w,
|
||||
};
|
||||
selectedModelProperties.glowLevel = 0.0;
|
||||
|
||||
print("Clicked on " + selectedModelID.id + " " + modelSelected);
|
||||
}
|
||||
}
|
||||
|
||||
Controller.mouseReleaseEvent.connect(function() {
|
||||
if (modelSelected) {
|
||||
Models.editModel(selectedModelID, { glowLevel: 0.0 });
|
||||
modelSelected = false;
|
||||
}
|
||||
});
|
||||
|
||||
var glowedModelID = { id: -1, isKnownID: false };
|
||||
var oldModifier = 0;
|
||||
var modifier = 0;
|
||||
var wasShifted = false;
|
||||
function mouseMoveEvent(event) {
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
|
||||
if (!modelSelected) {
|
||||
var modelIntersection = Models.findRayIntersection(pickRay);
|
||||
if (modelIntersection.accurate) {
|
||||
if(glowedModelID.isKnownID && glowedModelID.id != modelIntersection.modelID.id) {
|
||||
Models.editModel(glowedModelID, { glowLevel: 0.0 });
|
||||
glowedModelID.id = -1;
|
||||
glowedModelID.isKnownID = false;
|
||||
}
|
||||
|
||||
if (modelIntersection.modelID.isKnownID) {
|
||||
Models.editModel(modelIntersection.modelID, { glowLevel: 0.25 });
|
||||
glowedModelID = modelIntersection.modelID;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -579,8 +587,7 @@ function mouseMoveEvent(event) {
|
|||
} else {
|
||||
modifier = 0;
|
||||
}
|
||||
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
pickRay = Camera.computePickRay(event.x, event.y);
|
||||
if (wasShifted != event.isShifted || modifier != oldModifier) {
|
||||
selectedModelProperties.oldRadius = selectedModelProperties.radius;
|
||||
|
||||
|
@ -653,6 +660,15 @@ function mouseMoveEvent(event) {
|
|||
Models.editModel(selectedModelID, selectedModelProperties);
|
||||
}
|
||||
|
||||
function mouseReleaseEvent(event) {
|
||||
modelSelected = false;
|
||||
|
||||
glowedModelID.id = -1;
|
||||
glowedModelID.isKnownID = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setupModelMenus() {
|
||||
// add our menuitems
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Models", isSeparator: true, beforeItem: "Physics" });
|
||||
|
@ -677,6 +693,7 @@ Script.scriptEnding.connect(scriptEnding);
|
|||
Script.update.connect(checkController);
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
||||
|
||||
setupModelMenus();
|
||||
Menu.menuItemEvent.connect(function(menuItem){
|
||||
|
|
|
@ -17,6 +17,9 @@ uniform sampler2D diffuseMap;
|
|||
// the shadow texture
|
||||
uniform sampler2DShadow shadowMap;
|
||||
|
||||
// the inverse of the size of the shadow map
|
||||
const float shadowScale = 1.0 / 2048.0;
|
||||
|
||||
// the interpolated position
|
||||
varying vec4 position;
|
||||
|
||||
|
@ -27,7 +30,11 @@ void main(void) {
|
|||
// compute the base color based on OpenGL lighting model
|
||||
vec4 normalizedNormal = normalize(normal);
|
||||
float diffuse = dot(normalizedNormal, gl_LightSource[0].position);
|
||||
float facingLight = step(0.0, diffuse) * shadow2D(shadowMap, gl_TexCoord[1].stp).r;
|
||||
float facingLight = step(0.0, diffuse) * 0.25 *
|
||||
(shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, shadowScale, 0.0)).r);
|
||||
vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient +
|
||||
gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));
|
||||
|
||||
|
|
|
@ -20,6 +20,9 @@ uniform sampler2D normalMap;
|
|||
// the shadow texture
|
||||
uniform sampler2DShadow shadowMap;
|
||||
|
||||
// the inverse of the size of the shadow map
|
||||
const float shadowScale = 1.0 / 2048.0;
|
||||
|
||||
// the interpolated position
|
||||
varying vec4 interpolatedPosition;
|
||||
|
||||
|
@ -39,7 +42,11 @@ void main(void) {
|
|||
vec4 viewNormal = vec4(normalizedTangent * localNormal.x +
|
||||
normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0);
|
||||
float diffuse = dot(viewNormal, gl_LightSource[0].position);
|
||||
float facingLight = step(0.0, diffuse) * shadow2D(shadowMap, gl_TexCoord[1].stp).r;
|
||||
float facingLight = step(0.0, diffuse) * 0.25 *
|
||||
(shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, shadowScale, 0.0)).r);
|
||||
vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient +
|
||||
gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));
|
||||
|
||||
|
|
|
@ -23,6 +23,9 @@ uniform sampler2D specularMap;
|
|||
// the shadow texture
|
||||
uniform sampler2DShadow shadowMap;
|
||||
|
||||
// the inverse of the size of the shadow map
|
||||
const float shadowScale = 1.0 / 2048.0;
|
||||
|
||||
// the interpolated position
|
||||
varying vec4 interpolatedPosition;
|
||||
|
||||
|
@ -42,7 +45,11 @@ void main(void) {
|
|||
vec4 viewNormal = vec4(normalizedTangent * localNormal.x +
|
||||
normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0);
|
||||
float diffuse = dot(viewNormal, gl_LightSource[0].position);
|
||||
float facingLight = step(0.0, diffuse) * shadow2D(shadowMap, gl_TexCoord[1].stp).r;
|
||||
float facingLight = step(0.0, diffuse) * 0.25 *
|
||||
(shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, shadowScale, 0.0)).r);
|
||||
vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient +
|
||||
gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));
|
||||
|
||||
|
|
|
@ -20,6 +20,9 @@ uniform sampler2D specularMap;
|
|||
// the shadow texture
|
||||
uniform sampler2DShadow shadowMap;
|
||||
|
||||
// the inverse of the size of the shadow map
|
||||
const float shadowScale = 1.0 / 2048.0;
|
||||
|
||||
// the interpolated position in view space
|
||||
varying vec4 position;
|
||||
|
||||
|
@ -30,7 +33,11 @@ void main(void) {
|
|||
// compute the base color based on OpenGL lighting model
|
||||
vec4 normalizedNormal = normalize(normal);
|
||||
float diffuse = dot(normalizedNormal, gl_LightSource[0].position);
|
||||
float facingLight = step(0.0, diffuse) * shadow2D(shadowMap, gl_TexCoord[1].stp).r;
|
||||
float facingLight = step(0.0, diffuse) * 0.25 *
|
||||
(shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, shadowScale, 0.0)).r);
|
||||
vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient +
|
||||
gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));
|
||||
|
||||
|
|
|
@ -164,6 +164,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
_previousScriptLocation(),
|
||||
_runningScriptsWidget(new RunningScriptsWidget(_window)),
|
||||
_runningScriptsWidgetWasVisible(false),
|
||||
_trayIcon(new QSystemTrayIcon(_window)),
|
||||
_overlayRenderer()
|
||||
{
|
||||
// read the ApplicationInfo.ini file for Name/Version/Domain information
|
||||
|
@ -234,7 +235,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
QTimer* locationUpdateTimer = new QTimer(this);
|
||||
connect(locationUpdateTimer, &QTimer::timeout, this, &Application::updateLocationInServer);
|
||||
locationUpdateTimer->start(DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS);
|
||||
|
||||
|
||||
connect(nodeList, &NodeList::nodeAdded, this, &Application::nodeAdded);
|
||||
connect(nodeList, &NodeList::nodeKilled, this, &Application::nodeKilled);
|
||||
connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer)));
|
||||
|
@ -243,16 +244,16 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
connect(nodeList, &NodeList::uuidChanged, this, &Application::updateWindowTitle);
|
||||
connect(nodeList, SIGNAL(uuidChanged(const QUuid&)), _myAvatar, SLOT(setSessionUUID(const QUuid&)));
|
||||
connect(nodeList, &NodeList::limitOfSilentDomainCheckInsReached, nodeList, &NodeList::reset);
|
||||
|
||||
|
||||
// connect to appropriate slots on AccountManager
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
|
||||
|
||||
const qint64 BALANCE_UPDATE_INTERVAL_MSECS = 5 * 1000;
|
||||
|
||||
|
||||
QTimer* balanceUpdateTimer = new QTimer(this);
|
||||
connect(balanceUpdateTimer, &QTimer::timeout, &accountManager, &AccountManager::updateBalance);
|
||||
balanceUpdateTimer->start(BALANCE_UPDATE_INTERVAL_MSECS);
|
||||
|
||||
|
||||
connect(&accountManager, &AccountManager::balanceChanged, this, &Application::updateWindowTitle);
|
||||
|
||||
connect(&accountManager, &AccountManager::authRequired, Menu::getInstance(), &Menu::loginForCurrentDomain);
|
||||
|
@ -383,6 +384,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
OAuthWebViewHandler::getInstance();
|
||||
// make sure the High Fidelity root CA is in our list of trusted certs
|
||||
OAuthWebViewHandler::addHighFidelityRootCAToSSLConfig();
|
||||
|
||||
_trayIcon->show();
|
||||
}
|
||||
|
||||
Application::~Application() {
|
||||
|
@ -554,7 +557,7 @@ void Application::paintGL() {
|
|||
PerformanceWarning warn(showWarnings, "Application::paintGL()");
|
||||
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
|
||||
|
||||
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
|
||||
_myCamera.setTightness(0.0f); // In first person, camera follows (untweaked) head exactly without delay
|
||||
_myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition());
|
||||
|
@ -2319,10 +2322,15 @@ void Application::updateShadowMap() {
|
|||
// store view matrix without translation, which we'll use for precision-sensitive objects
|
||||
updateUntranslatedViewMatrix();
|
||||
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(1.1f, 4.0f); // magic numbers courtesy http://www.eecs.berkeley.edu/~ravir/6160/papers/shadowmaps.ppt
|
||||
|
||||
_avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE);
|
||||
_particles.render(OctreeRenderer::SHADOW_RENDER_MODE);
|
||||
_models.render(OctreeRenderer::SHADOW_RENDER_MODE);
|
||||
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
|
@ -2922,18 +2930,18 @@ void Application::updateWindowTitle(){
|
|||
QString username = AccountManager::getInstance().getAccountInfo().getUsername();
|
||||
QString title = QString() + (!username.isEmpty() ? username + " @ " : QString())
|
||||
+ nodeList->getDomainHandler().getHostname() + buildVersion;
|
||||
|
||||
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
if (accountManager.getAccountInfo().hasBalance()) {
|
||||
float creditBalance = accountManager.getAccountInfo().getBalance() / SATOSHIS_PER_CREDIT;
|
||||
|
||||
|
||||
QString creditBalanceString;
|
||||
creditBalanceString.sprintf("%.8f", creditBalance);
|
||||
|
||||
|
||||
title += " - ₵" + creditBalanceString;
|
||||
}
|
||||
|
||||
qDebug("Application title set to: %s", title.toStdString().c_str());
|
||||
|
||||
qDebug("Application title set to: %s", title.toStdString().c_str());
|
||||
_window->setWindowTitle(title);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <QHash>
|
||||
#include <QTouchEvent>
|
||||
#include <QUndoStack>
|
||||
#include <QSystemTrayIcon>
|
||||
|
||||
#include <ModelEditPacketSender.h>
|
||||
#include <NetworkPacket.h>
|
||||
|
@ -214,6 +215,7 @@ public:
|
|||
JoystickManager* getJoystickManager() { return &_joystickManager; }
|
||||
BandwidthMeter* getBandwidthMeter() { return &_bandwidthMeter; }
|
||||
QUndoStack* getUndoStack() { return &_undoStack; }
|
||||
QSystemTrayIcon* getTrayIcon() { return _trayIcon; }
|
||||
OverlayRenderer& getOverlayRenderer() { return _overlayRenderer; }
|
||||
Overlays& getOverlays() { return _overlays; }
|
||||
|
||||
|
@ -484,7 +486,7 @@ private:
|
|||
glm::mat4 _untranslatedViewMatrix;
|
||||
glm::vec3 _viewMatrixTranslation;
|
||||
glm::mat4 _projectionMatrix;
|
||||
|
||||
|
||||
float _scaleMirror;
|
||||
float _rotateMirror;
|
||||
float _raiseMirror;
|
||||
|
@ -573,6 +575,8 @@ private:
|
|||
RunningScriptsWidget* _runningScriptsWidget;
|
||||
QHash<QString, ScriptEngine*> _scriptEnginesHash;
|
||||
bool _runningScriptsWidgetWasVisible;
|
||||
|
||||
QSystemTrayIcon* _trayIcon;
|
||||
};
|
||||
|
||||
#endif // hifi_Application_h
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <UUID.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "AccountManager.h"
|
||||
#include "Menu.h"
|
||||
#include "scripting/MenuScriptingInterface.h"
|
||||
#include "Util.h"
|
||||
|
@ -195,12 +196,12 @@ Menu::Menu() :
|
|||
|
||||
addActionToQMenuAndActionHash(editMenu, MenuOption::Attachments, 0, this, SLOT(editAttachments()));
|
||||
addActionToQMenuAndActionHash(editMenu, MenuOption::Animations, 0, this, SLOT(editAnimations()));
|
||||
|
||||
|
||||
addDisabledActionAndSeparator(editMenu, "Physics");
|
||||
QObject* avatar = appInstance->getAvatar();
|
||||
addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::ObeyEnvironmentalGravity, Qt::SHIFT | Qt::Key_G, false,
|
||||
addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::ObeyEnvironmentalGravity, Qt::SHIFT | Qt::Key_G, false,
|
||||
avatar, SLOT(updateMotionBehaviorsFromMenu()));
|
||||
addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::StandOnNearbyFloors, 0, true,
|
||||
addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::StandOnNearbyFloors, 0, true,
|
||||
avatar, SLOT(updateMotionBehaviorsFromMenu()));
|
||||
|
||||
addAvatarCollisionSubMenu(editMenu);
|
||||
|
@ -332,6 +333,7 @@ Menu::Menu() :
|
|||
|
||||
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::AllowOculusCameraModeChange, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Avatars, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::AvatarsReceiveShadows, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::RenderSkeletonCollisionShapes);
|
||||
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::RenderHeadCollisionShapes);
|
||||
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::RenderBoundingCollisionShapes);
|
||||
|
@ -1026,24 +1028,24 @@ void Menu::multipleDestinationsDecision(const QJsonObject& userData, const QJson
|
|||
void Menu::muteEnvironment() {
|
||||
int headerSize = numBytesForPacketHeaderGivenPacketType(PacketTypeMuteEnvironment);
|
||||
int packetSize = headerSize + sizeof(glm::vec3) + sizeof(float);
|
||||
|
||||
|
||||
glm::vec3 position = Application::getInstance()->getAvatar()->getPosition();
|
||||
|
||||
|
||||
char* packet = (char*)malloc(packetSize);
|
||||
populatePacketHeader(packet, PacketTypeMuteEnvironment);
|
||||
memcpy(packet + headerSize, &position, sizeof(glm::vec3));
|
||||
memcpy(packet + headerSize + sizeof(glm::vec3), &MUTE_RADIUS, sizeof(float));
|
||||
|
||||
|
||||
QByteArray mutePacket(packet, packetSize);
|
||||
|
||||
|
||||
// grab our audio mixer from the NodeList, if it exists
|
||||
SharedNodePointer audioMixer = NodeList::getInstance()->soloNodeOfType(NodeType::AudioMixer);
|
||||
|
||||
|
||||
if (audioMixer) {
|
||||
// send off this mute packet
|
||||
NodeList::getInstance()->writeDatagram(mutePacket, audioMixer);
|
||||
}
|
||||
|
||||
|
||||
free(packet);
|
||||
}
|
||||
|
||||
|
@ -1201,19 +1203,24 @@ void Menu::showScriptEditor() {
|
|||
}
|
||||
|
||||
void Menu::showChat() {
|
||||
QMainWindow* mainWindow = Application::getInstance()->getWindow();
|
||||
if (!_chatWindow) {
|
||||
_chatWindow = new ChatWindow(mainWindow);
|
||||
}
|
||||
if (_chatWindow->isHidden()) {
|
||||
_chatWindow->show();
|
||||
if (AccountManager::getInstance().isLoggedIn()) {
|
||||
QMainWindow* mainWindow = Application::getInstance()->getWindow();
|
||||
if (!_chatWindow) {
|
||||
_chatWindow = new ChatWindow(mainWindow);
|
||||
}
|
||||
|
||||
if (_chatWindow->isHidden()) {
|
||||
_chatWindow->show();
|
||||
}
|
||||
} else {
|
||||
Application::getInstance()->getTrayIcon()->showMessage("Interface", "You need to login to be able to chat with others on this domain.");
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::toggleChat() {
|
||||
#ifdef HAVE_QXMPP
|
||||
_chatAction->setEnabled(XmppClient::getInstance().getXMPPClient().isConnected());
|
||||
if (!_chatAction->isEnabled() && _chatWindow) {
|
||||
if (!_chatAction->isEnabled() && _chatWindow && AccountManager::getInstance().isLoggedIn()) {
|
||||
if (_chatWindow->isHidden()) {
|
||||
_chatWindow->show();
|
||||
} else {
|
||||
|
|
|
@ -293,6 +293,7 @@ namespace MenuOption {
|
|||
const QString AudioSpatialProcessingDontDistanceAttenuate = "Don't calculate distance attenuation";
|
||||
const QString AudioSpatialProcessingAlternateDistanceAttenuate = "Alternate distance attenuation";
|
||||
const QString Avatars = "Avatars";
|
||||
const QString AvatarsReceiveShadows = "Avatars Receive Shadows";
|
||||
const QString Bandwidth = "Bandwidth Display";
|
||||
const QString BandwidthDetails = "Bandwidth Details";
|
||||
const QString BuckyBalls = "Bucky Balls";
|
||||
|
|
|
@ -347,7 +347,6 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
|
|||
void Avatar::renderBody(RenderMode renderMode, float glowLevel) {
|
||||
Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ?
|
||||
Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
|
||||
|
||||
{
|
||||
Glower glower(glowLevel);
|
||||
|
||||
|
@ -356,7 +355,8 @@ void Avatar::renderBody(RenderMode renderMode, float glowLevel) {
|
|||
renderBillboard();
|
||||
return;
|
||||
}
|
||||
_skeletonModel.render(1.0f, modelRenderMode);
|
||||
|
||||
_skeletonModel.render(1.0f, modelRenderMode, Menu::getInstance()->isOptionChecked(MenuOption::AvatarsReceiveShadows));
|
||||
renderAttachments(renderMode);
|
||||
getHand()->render(false, modelRenderMode);
|
||||
}
|
||||
|
@ -390,8 +390,9 @@ void Avatar::simulateAttachments(float deltaTime) {
|
|||
void Avatar::renderAttachments(RenderMode renderMode) {
|
||||
Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ?
|
||||
Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
|
||||
bool receiveShadows = Menu::getInstance()->isOptionChecked(MenuOption::AvatarsReceiveShadows);
|
||||
foreach (Model* model, _attachmentModels) {
|
||||
model->render(1.0f, modelRenderMode);
|
||||
model->render(1.0f, modelRenderMode, receiveShadows);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -176,7 +176,8 @@ void Head::relaxLean(float deltaTime) {
|
|||
}
|
||||
|
||||
void Head::render(float alpha, Model::RenderMode mode) {
|
||||
if (_faceModel.render(alpha, mode) && _renderLookatVectors && mode != Model::SHADOW_RENDER_MODE) {
|
||||
if (_faceModel.render(alpha, mode, Menu::getInstance()->isOptionChecked(MenuOption::AvatarsReceiveShadows)) &&
|
||||
_renderLookatVectors && mode != Model::SHADOW_RENDER_MODE) {
|
||||
renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -773,7 +773,7 @@ void MyAvatar::renderBody(RenderMode renderMode, float glowLevel) {
|
|||
// Render the body's voxels and head
|
||||
Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ?
|
||||
Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
|
||||
_skeletonModel.render(1.0f, modelRenderMode);
|
||||
_skeletonModel.render(1.0f, modelRenderMode, Menu::getInstance()->isOptionChecked(MenuOption::AvatarsReceiveShadows));
|
||||
renderAttachments(renderMode);
|
||||
|
||||
// Render head so long as the camera isn't inside it
|
||||
|
@ -1695,10 +1695,11 @@ void MyAvatar::renderAttachments(RenderMode renderMode) {
|
|||
QString headJointName = (geometry.headJointIndex == -1) ? QString() : geometry.joints.at(geometry.headJointIndex).name;
|
||||
Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ?
|
||||
Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
|
||||
bool receiveShadows = Menu::getInstance()->isOptionChecked(MenuOption::AvatarsReceiveShadows);
|
||||
for (int i = 0; i < _attachmentData.size(); i++) {
|
||||
const QString& jointName = _attachmentData.at(i).jointName;
|
||||
if (jointName != headJointName && jointName != "Head") {
|
||||
_attachmentModels.at(i)->render(1.0f, modelRenderMode);
|
||||
_attachmentModels.at(i)->render(1.0f, modelRenderMode, receiveShadows);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
#include <FBXReader.h>
|
||||
|
||||
#include "InterfaceConfig.h"
|
||||
#include "Menu.h"
|
||||
#include "ModelTreeRenderer.h"
|
||||
|
@ -34,8 +36,13 @@ ModelTreeRenderer::~ModelTreeRenderer() {
|
|||
|
||||
void ModelTreeRenderer::init() {
|
||||
OctreeRenderer::init();
|
||||
static_cast<ModelTree*>(_tree)->setFBXService(this);
|
||||
}
|
||||
|
||||
void ModelTreeRenderer::setTree(Octree* newTree) {
|
||||
OctreeRenderer::setTree(newTree);
|
||||
static_cast<ModelTree*>(_tree)->setFBXService(this);
|
||||
}
|
||||
|
||||
void ModelTreeRenderer::update() {
|
||||
if (_tree) {
|
||||
|
@ -48,6 +55,16 @@ void ModelTreeRenderer::render(RenderMode renderMode) {
|
|||
OctreeRenderer::render(renderMode);
|
||||
}
|
||||
|
||||
const FBXGeometry* ModelTreeRenderer::getGeometryForModel(const ModelItem& modelItem) {
|
||||
const FBXGeometry* result = NULL;
|
||||
Model* model = getModel(modelItem);
|
||||
if (model) {
|
||||
result = &model->getGeometry()->getFBXGeometry();
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Model* ModelTreeRenderer::getModel(const ModelItem& modelItem) {
|
||||
Model* model = NULL;
|
||||
|
||||
|
@ -73,42 +90,6 @@ Model* ModelTreeRenderer::getModel(const ModelItem& modelItem) {
|
|||
return model;
|
||||
}
|
||||
|
||||
void calculateRotatedExtents(Extents& extents, const glm::quat& rotation) {
|
||||
glm::vec3 bottomLeftNear(extents.minimum.x, extents.minimum.y, extents.minimum.z);
|
||||
glm::vec3 bottomRightNear(extents.maximum.x, extents.minimum.y, extents.minimum.z);
|
||||
glm::vec3 bottomLeftFar(extents.minimum.x, extents.minimum.y, extents.maximum.z);
|
||||
glm::vec3 bottomRightFar(extents.maximum.x, extents.minimum.y, extents.maximum.z);
|
||||
glm::vec3 topLeftNear(extents.minimum.x, extents.maximum.y, extents.minimum.z);
|
||||
glm::vec3 topRightNear(extents.maximum.x, extents.maximum.y, extents.minimum.z);
|
||||
glm::vec3 topLeftFar(extents.minimum.x, extents.maximum.y, extents.maximum.z);
|
||||
glm::vec3 topRightFar(extents.maximum.x, extents.maximum.y, extents.maximum.z);
|
||||
|
||||
glm::vec3 bottomLeftNearRotated = rotation * bottomLeftNear;
|
||||
glm::vec3 bottomRightNearRotated = rotation * bottomRightNear;
|
||||
glm::vec3 bottomLeftFarRotated = rotation * bottomLeftFar;
|
||||
glm::vec3 bottomRightFarRotated = rotation * bottomRightFar;
|
||||
glm::vec3 topLeftNearRotated = rotation * topLeftNear;
|
||||
glm::vec3 topRightNearRotated = rotation * topRightNear;
|
||||
glm::vec3 topLeftFarRotated = rotation * topLeftFar;
|
||||
glm::vec3 topRightFarRotated = rotation * topRightFar;
|
||||
|
||||
extents.minimum = glm::min(bottomLeftNearRotated,
|
||||
glm::min(bottomRightNearRotated,
|
||||
glm::min(bottomLeftFarRotated,
|
||||
glm::min(bottomRightFarRotated,
|
||||
glm::min(topLeftNearRotated,
|
||||
glm::min(topRightNearRotated,
|
||||
glm::min(topLeftFarRotated,topRightFarRotated)))))));
|
||||
|
||||
extents.maximum = glm::max(bottomLeftNearRotated,
|
||||
glm::max(bottomRightNearRotated,
|
||||
glm::max(bottomLeftFarRotated,
|
||||
glm::max(bottomRightFarRotated,
|
||||
glm::max(topLeftNearRotated,
|
||||
glm::max(topRightNearRotated,
|
||||
glm::max(topLeftFarRotated,topRightFarRotated)))))));
|
||||
}
|
||||
|
||||
void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) {
|
||||
args->_elementsTouched++;
|
||||
// actually render it here...
|
||||
|
@ -248,6 +229,7 @@ void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
|
|||
}
|
||||
|
||||
if (!isShadowMode && displayModelBounds) {
|
||||
|
||||
glm::vec3 unRotatedMinimum = model->getUnscaledMeshExtents().minimum;
|
||||
glm::vec3 unRotatedMaximum = model->getUnscaledMeshExtents().maximum;
|
||||
glm::vec3 unRotatedExtents = unRotatedMaximum - unRotatedMinimum;
|
||||
|
@ -285,6 +267,7 @@ void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
|
|||
glutWireCube(1.0);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include "renderer/Model.h"
|
||||
|
||||
// Generic client side Octree renderer class.
|
||||
class ModelTreeRenderer : public OctreeRenderer {
|
||||
class ModelTreeRenderer : public OctreeRenderer, public ModelItemFBXService {
|
||||
public:
|
||||
ModelTreeRenderer();
|
||||
virtual ~ModelTreeRenderer();
|
||||
|
@ -38,6 +38,7 @@ public:
|
|||
virtual void renderElement(OctreeElement* element, RenderArgs* args);
|
||||
virtual float getSizeScale() const;
|
||||
virtual int getBoundaryLevelAdjust() const;
|
||||
virtual void setTree(Octree* newTree);
|
||||
|
||||
void update();
|
||||
|
||||
|
@ -48,6 +49,8 @@ public:
|
|||
virtual void init();
|
||||
virtual void render(RenderMode renderMode = DEFAULT_RENDER_MODE);
|
||||
|
||||
virtual const FBXGeometry* getGeometryForModel(const ModelItem& modelItem);
|
||||
|
||||
protected:
|
||||
Model* getModel(const ModelItem& modelItem);
|
||||
QMap<uint32_t, Model*> _knownModelsItemModels;
|
||||
|
|
|
@ -470,7 +470,7 @@ bool Model::updateGeometry() {
|
|||
return needFullUpdate;
|
||||
}
|
||||
|
||||
bool Model::render(float alpha, RenderMode mode) {
|
||||
bool Model::render(float alpha, RenderMode mode, bool receiveShadows) {
|
||||
// render the attachments
|
||||
foreach (Model* attachment, _attachments) {
|
||||
attachment->render(alpha, mode);
|
||||
|
@ -498,6 +498,9 @@ bool Model::render(float alpha, RenderMode mode) {
|
|||
glDisable(GL_CULL_FACE);
|
||||
} else {
|
||||
glEnable(GL_CULL_FACE);
|
||||
if (mode == SHADOW_RENDER_MODE) {
|
||||
glCullFace(GL_FRONT);
|
||||
}
|
||||
}
|
||||
|
||||
// render opaque meshes with alpha testing
|
||||
|
@ -505,16 +508,21 @@ bool Model::render(float alpha, RenderMode mode) {
|
|||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_GREATER, 0.5f * alpha);
|
||||
|
||||
renderMeshes(alpha, mode, false);
|
||||
receiveShadows &= Menu::getInstance()->isOptionChecked(MenuOption::Shadows);
|
||||
renderMeshes(alpha, mode, false, receiveShadows);
|
||||
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
|
||||
// render translucent meshes afterwards
|
||||
|
||||
renderMeshes(alpha, mode, true);
|
||||
renderMeshes(alpha, mode, true, receiveShadows);
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
if (mode == SHADOW_RENDER_MODE) {
|
||||
glCullFace(GL_BACK);
|
||||
}
|
||||
|
||||
// deactivate vertex arrays after drawing
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
@ -1589,11 +1597,10 @@ void Model::deleteGeometry() {
|
|||
}
|
||||
}
|
||||
|
||||
void Model::renderMeshes(float alpha, RenderMode mode, bool translucent) {
|
||||
void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool receiveShadows) {
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
const QVector<NetworkMesh>& networkMeshes = _geometry->getMeshes();
|
||||
|
||||
bool receiveShadows = Menu::getInstance()->isOptionChecked(MenuOption::Shadows);
|
||||
if (receiveShadows) {
|
||||
glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[0]);
|
||||
glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[1]);
|
||||
|
|
|
@ -79,7 +79,7 @@ public:
|
|||
|
||||
enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE };
|
||||
|
||||
bool render(float alpha = 1.0f, RenderMode mode = DEFAULT_RENDER_MODE);
|
||||
bool render(float alpha = 1.0f, RenderMode mode = DEFAULT_RENDER_MODE, bool receiveShadows = true);
|
||||
|
||||
/// Sets the URL of the model to render.
|
||||
/// \param fallback the URL of a fallback model to render if the requested model fails to load
|
||||
|
@ -315,7 +315,7 @@ private:
|
|||
|
||||
void applyNextGeometry();
|
||||
void deleteGeometry();
|
||||
void renderMeshes(float alpha, RenderMode mode, bool translucent);
|
||||
void renderMeshes(float alpha, RenderMode mode, bool translucent, bool receiveShadows);
|
||||
QVector<JointState> createJointStates(const FBXGeometry& geometry);
|
||||
|
||||
QSharedPointer<NetworkGeometry> _baseGeometry; ///< reference required to prevent collection of base
|
||||
|
|
|
@ -2052,3 +2052,40 @@ FBXGeometry readSVO(const QByteArray& model) {
|
|||
|
||||
return geometry;
|
||||
}
|
||||
|
||||
void calculateRotatedExtents(Extents& extents, const glm::quat& rotation) {
|
||||
glm::vec3 bottomLeftNear(extents.minimum.x, extents.minimum.y, extents.minimum.z);
|
||||
glm::vec3 bottomRightNear(extents.maximum.x, extents.minimum.y, extents.minimum.z);
|
||||
glm::vec3 bottomLeftFar(extents.minimum.x, extents.minimum.y, extents.maximum.z);
|
||||
glm::vec3 bottomRightFar(extents.maximum.x, extents.minimum.y, extents.maximum.z);
|
||||
glm::vec3 topLeftNear(extents.minimum.x, extents.maximum.y, extents.minimum.z);
|
||||
glm::vec3 topRightNear(extents.maximum.x, extents.maximum.y, extents.minimum.z);
|
||||
glm::vec3 topLeftFar(extents.minimum.x, extents.maximum.y, extents.maximum.z);
|
||||
glm::vec3 topRightFar(extents.maximum.x, extents.maximum.y, extents.maximum.z);
|
||||
|
||||
glm::vec3 bottomLeftNearRotated = rotation * bottomLeftNear;
|
||||
glm::vec3 bottomRightNearRotated = rotation * bottomRightNear;
|
||||
glm::vec3 bottomLeftFarRotated = rotation * bottomLeftFar;
|
||||
glm::vec3 bottomRightFarRotated = rotation * bottomRightFar;
|
||||
glm::vec3 topLeftNearRotated = rotation * topLeftNear;
|
||||
glm::vec3 topRightNearRotated = rotation * topRightNear;
|
||||
glm::vec3 topLeftFarRotated = rotation * topLeftFar;
|
||||
glm::vec3 topRightFarRotated = rotation * topRightFar;
|
||||
|
||||
extents.minimum = glm::min(bottomLeftNearRotated,
|
||||
glm::min(bottomRightNearRotated,
|
||||
glm::min(bottomLeftFarRotated,
|
||||
glm::min(bottomRightFarRotated,
|
||||
glm::min(topLeftNearRotated,
|
||||
glm::min(topRightNearRotated,
|
||||
glm::min(topLeftFarRotated,topRightFarRotated)))))));
|
||||
|
||||
extents.maximum = glm::max(bottomLeftNearRotated,
|
||||
glm::max(bottomRightNearRotated,
|
||||
glm::max(bottomLeftFarRotated,
|
||||
glm::max(bottomRightFarRotated,
|
||||
glm::max(topLeftNearRotated,
|
||||
glm::max(topRightNearRotated,
|
||||
glm::max(topLeftFarRotated,topRightFarRotated)))))));
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,8 @@ public:
|
|||
bool containsPoint(const glm::vec3& point) const;
|
||||
|
||||
/// \return whether or not the extents are empty
|
||||
bool isEmpty() { return minimum == maximum; }
|
||||
bool isEmpty() const { return minimum == maximum; }
|
||||
bool isValid() const { return !((minimum == glm::vec3(FLT_MAX)) && (maximum == glm::vec3(-FLT_MAX))); }
|
||||
|
||||
glm::vec3 minimum;
|
||||
glm::vec3 maximum;
|
||||
|
@ -238,4 +239,6 @@ FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping);
|
|||
/// Reads SVO geometry from the supplied model data.
|
||||
FBXGeometry readSVO(const QByteArray& model);
|
||||
|
||||
void calculateRotatedExtents(Extents& extents, const glm::quat& rotation);
|
||||
|
||||
#endif // hifi_FBXReader_h
|
||||
|
|
|
@ -20,6 +20,11 @@ public:
|
|||
virtual void modelCreated(const ModelItem& newModel, const SharedNodePointer& senderNode) = 0;
|
||||
};
|
||||
|
||||
class ModelItemFBXService {
|
||||
public:
|
||||
virtual const FBXGeometry* getGeometryForModel(const ModelItem& modelItem) = 0;
|
||||
};
|
||||
|
||||
class ModelTree : public Octree {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
@ -74,6 +79,11 @@ public:
|
|||
|
||||
void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
||||
void handleAddModelResponse(const QByteArray& packet);
|
||||
|
||||
void setFBXService(ModelItemFBXService* service) { _fbxService = service; }
|
||||
const FBXGeometry* getGeometryForModel(const ModelItem& modelItem) {
|
||||
return _fbxService ? _fbxService->getGeometryForModel(modelItem) : NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
|
@ -96,6 +106,7 @@ private:
|
|||
|
||||
QReadWriteLock _recentlyDeletedModelsLock;
|
||||
QMultiMap<quint64, uint32_t> _recentlyDeletedModelItemIDs;
|
||||
ModelItemFBXService* _fbxService;
|
||||
};
|
||||
|
||||
#endif // hifi_ModelTree_h
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <FBXReader.h>
|
||||
#include <GeometryUtil.h>
|
||||
|
||||
#include "ModelTree.h"
|
||||
|
@ -158,7 +159,41 @@ bool ModelTreeElement::findDetailedRayIntersection(const glm::vec3& origin, cons
|
|||
|
||||
// if the ray doesn't intersect with our cube, we can stop searching!
|
||||
if (modelCube.findRayIntersection(origin, direction, localDistance, localFace)) {
|
||||
if (localDistance < distance) {
|
||||
const FBXGeometry* fbxGeometry = _myTree->getGeometryForModel(model);
|
||||
if (fbxGeometry && fbxGeometry->meshExtents.isValid()) {
|
||||
Extents extents = fbxGeometry->meshExtents;
|
||||
|
||||
// NOTE: these extents are model space, so we need to scale and center them accordingly
|
||||
// size is our "target size in world space"
|
||||
// we need to set our model scale so that the extents of the mesh, fit in a cube that size...
|
||||
float maxDimension = glm::distance(extents.maximum, extents.minimum);
|
||||
float scale = model.getSize() / maxDimension;
|
||||
|
||||
glm::vec3 halfDimensions = (extents.maximum - extents.minimum) * 0.5f;
|
||||
glm::vec3 offset = -extents.minimum - halfDimensions;
|
||||
|
||||
extents.minimum += offset;
|
||||
extents.maximum += offset;
|
||||
|
||||
extents.minimum *= scale;
|
||||
extents.maximum *= scale;
|
||||
|
||||
calculateRotatedExtents(extents, model.getModelRotation());
|
||||
|
||||
extents.minimum += model.getPosition();
|
||||
extents.maximum += model.getPosition();
|
||||
|
||||
AABox rotatedExtentsBox(extents.minimum, (extents.maximum - extents.minimum));
|
||||
|
||||
if (rotatedExtentsBox.findRayIntersection(origin, direction, localDistance, localFace)) {
|
||||
if (localDistance < distance) {
|
||||
distance = localDistance;
|
||||
face = localFace;
|
||||
*intersectedObject = (void*)(&model);
|
||||
somethingIntersected = true;
|
||||
}
|
||||
}
|
||||
} else if (localDistance < distance) {
|
||||
distance = localDistance;
|
||||
face = localFace;
|
||||
*intersectedObject = (void*)(&model);
|
||||
|
|
Loading…
Reference in a new issue