Merge branch 'master' of https://github.com/highfidelity/hifi into animationGroupSettings

This commit is contained in:
Brad Hefta-Gaub 2015-10-06 15:20:37 -07:00
commit be79101a93
42 changed files with 964 additions and 319 deletions

View file

@ -26,28 +26,28 @@ public:
~EntityServer();
// Subclasses must implement these methods
virtual OctreeQueryNode* createOctreeQueryNode();
virtual char getMyNodeType() const { return NodeType::EntityServer; }
virtual PacketType getMyQueryMessageType() const { return PacketType::EntityQuery; }
virtual const char* getMyServerName() const { return MODEL_SERVER_NAME; }
virtual const char* getMyLoggingServerTargetName() const { return MODEL_SERVER_LOGGING_TARGET_NAME; }
virtual const char* getMyDefaultPersistFilename() const { return LOCAL_MODELS_PERSIST_FILE; }
virtual PacketType getMyEditNackType() const { return PacketType::EntityEditNack; }
virtual QString getMyDomainSettingsKey() const { return QString("entity_server_settings"); }
virtual OctreeQueryNode* createOctreeQueryNode() override ;
virtual char getMyNodeType() const override { return NodeType::EntityServer; }
virtual PacketType getMyQueryMessageType() const override { return PacketType::EntityQuery; }
virtual const char* getMyServerName() const override { return MODEL_SERVER_NAME; }
virtual const char* getMyLoggingServerTargetName() const override { return MODEL_SERVER_LOGGING_TARGET_NAME; }
virtual const char* getMyDefaultPersistFilename() const override { return LOCAL_MODELS_PERSIST_FILE; }
virtual PacketType getMyEditNackType() const override { return PacketType::EntityEditNack; }
virtual QString getMyDomainSettingsKey() const override { return QString("entity_server_settings"); }
// subclass may implement these method
virtual void beforeRun();
virtual bool hasSpecialPacketsToSend(const SharedNodePointer& node);
virtual int sendSpecialPackets(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent);
virtual void beforeRun() override;
virtual bool hasSpecialPacketsToSend(const SharedNodePointer& node) override;
virtual int sendSpecialPackets(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent) override;
virtual void entityCreated(const EntityItem& newEntity, const SharedNodePointer& senderNode);
virtual void entityCreated(const EntityItem& newEntity, const SharedNodePointer& senderNode) override;
virtual bool readAdditionalConfiguration(const QJsonObject& settingsSectionObject) override;
public slots:
void pruneDeletedEntities();
protected:
virtual OctreePointer createTree();
virtual OctreePointer createTree() override;
private slots:
void handleEntityPacket(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode);

View file

@ -133,33 +133,14 @@ bool DomainServer::optionallyReadX509KeyAndCertificate() {
QString keyPath = _settingsManager.getSettingsMap().value(X509_PRIVATE_KEY_OPTION).toString();
if (!certPath.isEmpty() && !keyPath.isEmpty()) {
// the user wants to use DTLS to encrypt communication with nodes
// the user wants to use the following cert and key for HTTPS
// this is used for Oauth callbacks when authorizing users against a data server
// let's make sure we can load the key and certificate
// _x509Credentials = new gnutls_certificate_credentials_t;
// gnutls_certificate_allocate_credentials(_x509Credentials);
QString keyPassphraseString = QProcessEnvironment::systemEnvironment().value(X509_KEY_PASSPHRASE_ENV);
qDebug() << "Reading certificate file at" << certPath << "for DTLS.";
qDebug() << "Reading key file at" << keyPath << "for DTLS.";
// int gnutlsReturn = gnutls_certificate_set_x509_key_file2(*_x509Credentials,
// certPath.toLocal8Bit().constData(),
// keyPath.toLocal8Bit().constData(),
// GNUTLS_X509_FMT_PEM,
// keyPassphraseString.toLocal8Bit().constData(),
// 0);
//
// if (gnutlsReturn < 0) {
// qDebug() << "Unable to load certificate or key file." << "Error" << gnutlsReturn << "- domain-server will now quit.";
// QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection);
// return false;
// }
// qDebug() << "Successfully read certificate and private key.";
// we need to also pass this certificate and private key to the HTTPS manager
// this is used for Oauth callbacks when authorizing users against a data server
qDebug() << "Reading certificate file at" << certPath << "for HTTPS.";
qDebug() << "Reading key file at" << keyPath << "for HTTPS.";
QFile certFile(certPath);
certFile.open(QIODevice::ReadOnly);

View file

@ -79,23 +79,26 @@ var STATE_NEAR_GRABBING_NON_COLLIDING = 6;
var STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING = 7;
var STATE_RELEASE = 8;
var GRAB_USER_DATA_KEY = "grabKey";
var GRABBABLE_DATA_KEY = "grabbableKey";
var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js
var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js
function getTag() {
return "grab-" + MyAvatar.sessionUUID;
}
function entityIsGrabbedByOther(entityID) {
// by convention, a distance grab sets the tag of its action to be grab-*owner-session-id*.
var actionIDs = Entities.getActionIDs(entityID);
for (var actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) {
var actionID = actionIDs[actionIndex];
var actionArguments = Entities.getActionArguments(entityID, actionID);
var tag = actionArguments["tag"];
if (tag == getTag()) {
// we see a grab-*uuid* shaped tag, but it's our tag, so that's okay.
continue;
}
if (tag.slice(0, 5) == "grab-") {
// we see a grab-*uuid* shaped tag and it's not ours, so someone else is grabbing it.
return true;
}
}
@ -164,6 +167,12 @@ function MyController(hand, triggerAction) {
}
};
this.setState = function(newState) {
// print("STATE: " + this.state + " --> " + newState);
this.state = newState;
}
this.lineOn = function(closePoint, farPoint, color) {
// draw a line
if (this.pointer === null) {
@ -217,14 +226,14 @@ function MyController(hand, triggerAction) {
this.off = function() {
if (this.triggerSmoothedSqueezed()) {
this.state = STATE_SEARCHING;
this.setState(STATE_SEARCHING);
return;
}
}
this.search = function() {
if (this.triggerSmoothedReleased()) {
this.state = STATE_RELEASE;
this.setState(STATE_RELEASE);
return;
}
@ -235,6 +244,8 @@ function MyController(hand, triggerAction) {
direction: Quat.getUp(this.getHandRotation())
};
this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
var defaultGrabbableData = {
grabbable: true
};
@ -250,20 +261,20 @@ function MyController(hand, triggerAction) {
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, intersection.entityID, defaultGrabbableData);
if (grabbableData.grabbable === false) {
this.grabbedEntity = null;
return;
}
if (intersectionDistance < NEAR_PICK_MAX_DISTANCE) {
// the hand is very close to the intersected object. go into close-grabbing mode.
this.state = STATE_NEAR_GRABBING;
this.setState(STATE_NEAR_GRABBING);
} else {
// don't allow two people to distance grab the same object
if (entityIsGrabbedByOther(intersection.entityID)) {
// don't allow two people to distance grab the same object
return;
this.grabbedEntity = null;
} else {
// the hand is far from the intersected object. go into distance-holding mode
this.setState(STATE_DISTANCE_HOLDING);
}
// the hand is far from the intersected object. go into distance-holding mode
this.state = STATE_DISTANCE_HOLDING;
this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
}
} else {
// forward ray test failed, try sphere test.
@ -287,22 +298,22 @@ function MyController(hand, triggerAction) {
}
}
if (this.grabbedEntity === null) {
this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
// this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
} else if (props.locked === 0 && props.collisionsWillMove === 1) {
this.state = STATE_NEAR_GRABBING;
this.setState(STATE_NEAR_GRABBING);
} else if (props.collisionsWillMove === 0) {
// We have grabbed a non-physical object, so we want to trigger a non-colliding event as opposed to a grab event
this.state = STATE_NEAR_GRABBING_NON_COLLIDING;
this.setState(STATE_NEAR_GRABBING_NON_COLLIDING);
}
}
};
this.distanceHolding = function() {
var handControllerPosition = Controller.getSpatialControlPosition(this.palm);
var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm));
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation"]);
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation",
"gravity", "ignoreForCollisions"]);
// add the action and initialize some variables
this.currentObjectPosition = grabbedProperties.position;
@ -325,8 +336,8 @@ function MyController(hand, triggerAction) {
}
if (this.actionID !== null) {
this.state = STATE_CONTINUE_DISTANCE_HOLDING;
this.activateEntity(this.grabbedEntity);
this.setState(STATE_CONTINUE_DISTANCE_HOLDING);
this.activateEntity(this.grabbedEntity, grabbedProperties);
if (this.hand === RIGHT_HAND) {
Entities.callEntityMethod(this.grabbedEntity, "setRightHand");
} else {
@ -342,7 +353,7 @@ function MyController(hand, triggerAction) {
this.continueDistanceHolding = function() {
if (this.triggerSmoothedReleased()) {
this.state = STATE_RELEASE;
this.setState(STATE_RELEASE);
return;
}
@ -400,7 +411,7 @@ function MyController(hand, triggerAction) {
var now = Date.now();
var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds
this.computeReleaseVelocity(deltaPosition, deltaTime, false);
this.currentObjectPosition = newObjectPosition;
this.currentObjectTime = now;
@ -423,15 +434,15 @@ function MyController(hand, triggerAction) {
this.nearGrabbing = function() {
if (this.triggerSmoothedReleased()) {
this.state = STATE_RELEASE;
this.setState(STATE_RELEASE);
return;
}
this.lineOff();
this.activateEntity(this.grabbedEntity);
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation"]);
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity,
["position", "rotation", "gravity", "ignoreForCollisions"]);
this.activateEntity(this.grabbedEntity, grabbedProperties);
var handRotation = this.getHandRotation();
var handPosition = this.getHandPosition();
@ -444,7 +455,7 @@ function MyController(hand, triggerAction) {
var offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, offsetRotation)), offset);
this.actionID = NULL_ACTION_ID;
this.actionID = Entities.addAction("hold", this.grabbedEntity, {
this.actionID = Entities.addAction("kinematic-hold", this.grabbedEntity, {
hand: this.hand === RIGHT_HAND ? "right" : "left",
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
relativePosition: offsetPosition,
@ -454,7 +465,7 @@ function MyController(hand, triggerAction) {
if (this.actionID === NULL_ACTION_ID) {
this.actionID = null;
} else {
this.state = STATE_CONTINUE_NEAR_GRABBING;
this.setState(STATE_CONTINUE_NEAR_GRABBING);
if (this.hand === RIGHT_HAND) {
Entities.callEntityMethod(this.grabbedEntity, "setRightHand");
} else {
@ -471,7 +482,7 @@ function MyController(hand, triggerAction) {
this.continueNearGrabbing = function() {
if (this.triggerSmoothedReleased()) {
this.state = STATE_RELEASE;
this.setState(STATE_RELEASE);
return;
}
@ -498,7 +509,7 @@ function MyController(hand, triggerAction) {
this.nearGrabbingNonColliding = function() {
if (this.triggerSmoothedReleased()) {
this.state = STATE_RELEASE;
this.setState(STATE_RELEASE);
return;
}
if (this.hand === RIGHT_HAND) {
@ -507,12 +518,12 @@ function MyController(hand, triggerAction) {
Entities.callEntityMethod(this.grabbedEntity, "setLeftHand");
}
Entities.callEntityMethod(this.grabbedEntity, "startNearGrabNonColliding");
this.state = STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING;
this.setState(STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING);
};
this.continueNearGrabbingNonColliding = function() {
if (this.triggerSmoothedReleased()) {
this.state = STATE_RELEASE;
this.setState(STATE_RELEASE);
return;
}
Entities.callEntityMethod(this.grabbedEntity, "continueNearGrabbingNonColliding");
@ -623,27 +634,42 @@ function MyController(hand, triggerAction) {
this.grabbedVelocity = ZERO_VEC;
this.grabbedEntity = null;
this.actionID = null;
this.state = STATE_OFF;
this.setState(STATE_OFF);
};
this.cleanup = function() {
this.release();
};
this.activateEntity = function() {
var data = {
activated: true,
avatarId: MyAvatar.sessionUUID
};
setEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, data);
this.activateEntity = function(entityID, grabbedProperties) {
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
data["activated"] = true;
data["avatarId"] = MyAvatar.sessionUUID;
data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1;
// zero gravity and set ignoreForCollisions to true, but in a way that lets us put them back, after all grabs are done
if (data["refCount"] == 1) {
data["gravity"] = grabbedProperties.gravity;
data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions;
Entities.editEntity(entityID, {gravity: {x:0, y:0, z:0}, ignoreForCollisions: true});
}
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
};
this.deactivateEntity = function() {
var data = {
activated: false,
avatarId: null
};
setEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, data);
this.deactivateEntity = function(entityID) {
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
if (data && data["refCount"]) {
data["refCount"] = data["refCount"] - 1;
if (data["refCount"] < 1) {
Entities.editEntity(entityID, {
gravity: data["gravity"],
ignoreForCollisions: data["ignoreForCollisions"]
});
data = null;
}
} else {
data = null;
}
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
};
}

View file

@ -26,7 +26,8 @@ var IDENTITY_QUAT = {
z: 0,
w: 0
};
var GRABBABLE_DATA_KEY = "grabbableKey";
var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with handControllerGrab.js
var GRAB_USER_DATA_KEY = "grabKey"; // shared with handControllerGrab.js
var defaultGrabbableData = {
grabbable: true
@ -45,26 +46,25 @@ var IDENTITY_QUAT = {
z: 0,
w: 0
};
var ACTION_LIFETIME = 120; // 2 minutes
var ACTION_LIFETIME = 10; // seconds
function getTag() {
return "grab-" + MyAvatar.sessionUUID;
}
function entityIsGrabbedByOther(entityID) {
// by convention, a distance grab sets the tag of its action to be grab-*owner-session-id*.
var actionIDs = Entities.getActionIDs(entityID);
var actionIndex;
var actionID;
var actionArguments;
var tag;
for (actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) {
actionID = actionIDs[actionIndex];
actionArguments = Entities.getActionArguments(entityID, actionID);
tag = actionArguments.tag;
if (tag === getTag()) {
for (var actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) {
var actionID = actionIDs[actionIndex];
var actionArguments = Entities.getActionArguments(entityID, actionID);
var tag = actionArguments["tag"];
if (tag == getTag()) {
// we see a grab-*uuid* shaped tag, but it's our tag, so that's okay.
continue;
}
if (tag.slice(0, 5) === "grab-") {
if (tag.slice(0, 5) == "grab-") {
// we see a grab-*uuid* shaped tag and it's not ours, so someone else is grabbing it.
return true;
}
}
@ -248,7 +248,6 @@ Grabber = function() {
this.currentPosition = ZERO_VEC3;
this.planeNormal = ZERO_VEC3;
this.originalGravity = ZERO_VEC3;
// maxDistance is a function of the size of the object.
this.maxDistance;
@ -347,14 +346,11 @@ Grabber.prototype.pressEvent = function(event) {
return;
}
Entities.editEntity(clickedEntity, {
gravity: ZERO_VEC3
});
this.activateEntity(clickedEntity, entityProperties);
this.isGrabbing = true;
this.entityID = clickedEntity;
this.currentPosition = entityProperties.position;
this.originalGravity = entityProperties.gravity;
this.targetPosition = {
x: this.startPosition.x,
y: this.startPosition.y,
@ -380,12 +376,7 @@ Grabber.prototype.pressEvent = function(event) {
Grabber.prototype.releaseEvent = function() {
if (this.isGrabbing) {
if (Vec3.length(this.originalGravity) != 0) {
Entities.editEntity(this.entityID, {
gravity: this.originalGravity
});
}
this.deactivateEntity(this.entityID);
this.isGrabbing = false
Entities.deleteAction(this.entityID, this.actionID);
this.actionID = null;
@ -504,6 +495,39 @@ Grabber.prototype.keyPressEvent = function(event) {
this.computeNewGrabPlane();
}
Grabber.prototype.activateEntity = function(entityID, grabbedProperties) {
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
data["activated"] = true;
data["avatarId"] = MyAvatar.sessionUUID;
data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1;
// zero gravity and set ignoreForCollisions to true, but in a way that lets us put them back, after all grabs are done
if (data["refCount"] == 1) {
data["gravity"] = grabbedProperties.gravity;
data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions;
Entities.editEntity(entityID, {gravity: {x:0, y:0, z:0}, ignoreForCollisions: true});
}
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
};
Grabber.prototype.deactivateEntity = function(entityID) {
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
if (data && data["refCount"]) {
data["refCount"] = data["refCount"] - 1;
if (data["refCount"] < 1) {
Entities.editEntity(entityID, {
gravity: data["gravity"],
ignoreForCollisions: data["ignoreForCollisions"]
});
data = null;
}
} else {
data = null;
}
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
};
var grabber = new Grabber();
function pressEvent(event) {
@ -530,4 +554,4 @@ Controller.mousePressEvent.connect(pressEvent);
Controller.mouseMoveEvent.connect(moveEvent);
Controller.mouseReleaseEvent.connect(releaseEvent);
Controller.keyPressEvent.connect(keyPressEvent);
Controller.keyReleaseEvent.connect(keyReleaseEvent);
Controller.keyReleaseEvent.connect(keyReleaseEvent);

View file

@ -79,13 +79,21 @@ getEntityUserData = function(id) {
// Non-destructively modify the user data of an entity.
setEntityCustomData = function(customKey, id, data) {
var userData = getEntityUserData(id);
userData[customKey] = data;
if (data == null) {
delete userData[customKey];
} else {
userData[customKey] = data;
}
setEntityUserData(id, userData);
}
getEntityCustomData = function(customKey, id, defaultValue) {
var userData = getEntityUserData(id);
return userData[customKey] ? userData[customKey] : defaultValue;
if (undefined != userData[customKey]) {
return userData[customKey];
} else {
return defaultValue;
}
}
mergeObjects = function(proto, custom) {

View file

@ -13,8 +13,8 @@ Script.include("../../utilities.js");
var scriptURL = Script.resolvePath('pingPongGun.js');
var MODEL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/ping_pong_gun.fbx'
var COLLISION_HULL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/ping_pong_gun_collision_hull.obj';
var MODEL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/ping_pong_gun.fbx?123'
var COLLISION_HULL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/ping_pong_gun_collision_hull.obj?123';
var center = Vec3.sum(Vec3.sum(MyAvatar.position, {
x: 0,
@ -25,14 +25,15 @@ var center = Vec3.sum(Vec3.sum(MyAvatar.position, {
var pingPongGun = Entities.addEntity({
type: "Model",
modelURL: MODEL_URL,
shapeType: 'compound',
compoundShapeURL: COLLISION_HULL_URL,
shapeType:'box',
// shapeType: 'compound',
// compoundShapeURL: COLLISION_HULL_URL,
script: scriptURL,
position: center,
dimensions: {
x:0.67,
y: 0.14,
z: 0.09
x: 0.08,
y: 0.21,
z: 0.47
},
collisionsWillMove: true,
});
@ -40,4 +41,4 @@ var pingPongGun = Entities.addEntity({
function cleanUp() {
Entities.deleteEntity(pingPongGun);
}
Script.scriptEnding.connect(cleanUp);
Script.scriptEnding.connect(cleanUp);

View file

@ -21,14 +21,14 @@
//if the trigger value goes below this value, reload the gun.
var RELOAD_THRESHOLD = 0.95;
var GUN_TIP_FWD_OFFSET = 0.45;
var GUN_TIP_FWD_OFFSET =-0.35;
var GUN_TIP_UP_OFFSET = 0.040;
var GUN_FORCE = 15;
var GUN_FORCE = 9;
var BALL_RESTITUTION = 0.6;
var BALL_LINEAR_DAMPING = 0.4;
var BALL_GRAVITY = {
x: 0,
y: -9.8,
y: -4.8,
z: 0
};
@ -36,14 +36,14 @@
x: 0.04,
y: 0.04,
z: 0.04
}
};
var BALL_COLOR = {
red: 255,
green: 255,
blue: 255
}
};
PingPongGun.prototype = {
hand: null,
@ -68,7 +68,6 @@
},
continueNearGrab: function() {
if (this.whichHand === null) {
//only set the active hand once -- if we always read the current hand, our 'holding' hand will get overwritten
this.setWhichHand();
@ -81,10 +80,14 @@
},
releaseGrab: function() {
var _t = this;
this.canShootTimeout = Script.setTimeout(function() {
_t.canShoot = false;
}, 250)
var _this = this;
if (this.whichHand === this.hand) {
this.whichHand = null;
this.canShootTimeout = Script.setTimeout(function() {
_this.canShoot = false;
}, 250);
}
},
checkTriggerPressure: function(gunHand) {
@ -97,18 +100,20 @@
if (this.triggerValue < RELOAD_THRESHOLD) {
// print('RELOAD');
this.canShoot = true;
} else if (this.triggerValue >= RELOAD_THRESHOLD && this.canShoot === true) {
} else if (this.triggerValue >= RELOAD_THRESHOLD && this.canShoot === true && this.hand === this.whichHand) {
var gunProperties = Entities.getEntityProperties(this.entityID, ["position", "rotation"]);
this.shootBall(gunProperties);
this.canShoot = false;
}
return;
},
shootBall: function(gunProperties) {
var forwardVec = Quat.getFront(Quat.multiply(gunProperties.rotation, Quat.fromPitchYawRollDegrees(0, -90, 0)));
var forwardVec = Quat.getFront(Quat.multiply(gunProperties.rotation, Quat.fromPitchYawRollDegrees(0, 180, 0)));
forwardVec = Vec3.normalize(forwardVec);
forwardVec = Vec3.multiply(forwardVec, GUN_FORCE);
var properties = {
type: 'Sphere',
color: BALL_COLOR,
@ -130,7 +135,7 @@
playSoundAtCurrentPosition: function(position) {
var audioProperties = {
volume: 0.1,
volume: 0.2,
position: position
};
@ -139,12 +144,14 @@
getGunTipPosition: function(properties) {
//the tip of the gun is going to be in a different place than the center, so we move in space relative to the model to find that position
var frontVector = Quat.getRight(properties.rotation);
var frontVector = Quat.getFront(properties.rotation);
var frontOffset = Vec3.multiply(frontVector, GUN_TIP_FWD_OFFSET);
var upVector = Quat.getRight(properties.rotation);
var upVector = Quat.getUp(properties.rotation);
var upOffset = Vec3.multiply(upVector, GUN_TIP_UP_OFFSET);
var gunTipPosition = Vec3.sum(properties.position, frontOffset);
gunTipPosition = Vec3.sum(gunTipPosition, upOffset);
return gunTipPosition;
},

View file

@ -9,7 +9,7 @@
//
(function() {
(function () {
// Script.include("../libraries/utils.js");
//Need absolute path for now, for testing before PR merge and s3 cloning. Will change post-merge
@ -33,19 +33,19 @@
var MIN_POINT_DISTANCE = 0.01;
var STROKE_WIDTH = 0.02;
this.setRightHand = function() {
this.setRightHand = function () {
this.hand = 'RIGHT';
}
this.setLeftHand = function() {
this.setLeftHand = function () {
this.hand = 'LEFT';
}
this.startNearGrab = function() {
this.startNearGrab = function () {
this.whichHand = this.hand;
}
this.toggleWithTriggerPressure = function() {
this.toggleWithTriggerPressure = function () {
var handClickString = this.whichHand + "_HAND_CLICK";
var handClick = Controller.findAction(handClickString);
@ -60,7 +60,7 @@
}
}
this.enableStream = function() {
this.enableStream = function () {
var position = Entities.getEntityProperties(this.entityId, "position").position;
var PI = 3.141593;
var DEG_TO_RAD = PI / 180.0;
@ -78,6 +78,11 @@
particleRadius: 0.01,
radiusSpread: 0.005,
polarFinish: 0.05,
colorStart: {
red: 50,
green: 10,
blue: 150
},
color: {
red: 170,
green: 20,
@ -98,11 +103,11 @@
}
this.releaseGrab = function() {
this.releaseGrab = function () {
this.disableStream();
}
this.disableStream = function() {
this.disableStream = function () {
Entities.deleteEntity(this.paintStream);
this.paintStream = null;
this.spraying = false;
@ -110,7 +115,7 @@
}
this.continueNearGrab = function() {
this.continueNearGrab = function () {
this.toggleWithTriggerPressure();
@ -136,7 +141,7 @@
});
}
this.preload = function(entityId) {
this.preload = function (entityId) {
this.sprayVolume = 0.1;
this.spraying = false;
this.entityId = entityId;
@ -144,12 +149,9 @@
}
this.unload = function() {
this.unload = function () {
if (this.paintStream) {
Entities.deleteEntity(this.paintStream);
}
this.strokes.forEach(function(stroke) {
Entities.deleteEntity(stroke);
});
}
});

View file

@ -0,0 +1,68 @@
//
// MonoHMD.js
//
// Created by Chris Collins on 10/5/15
// Copyright 2015 High Fidelity, Inc.
//
// This script allows you to switch between mono and stereo mode within the HMD.
// It will add adition menu to Tools called "IPD".
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
function setupipdMenu() {
if (!Menu.menuExists("Tools > IPD")) {
Menu.addMenu("Tools > IPD");
}
if (!Menu.menuItemExists("Tools > IPD", "Stereo")) {
Menu.addMenuItem({
menuName: "Tools > IPD",
menuItemName: "Stereo",
isCheckable: true,
isChecked: true
});
}
if (!Menu.menuItemExists("Tools > IPD", "Mono")) {
Menu.addMenuItem({
menuName: "Tools > IPD",
menuItemName: "Mono",
isCheckable: true,
isChecked: false
});
}
}
function menuItemEvent(menuItem) {
if (menuItem == "Stereo") {
Menu.setIsOptionChecked("Mono", false);
HMD.ipdScale = 1.0;
}
if (menuItem == "Mono") {
Menu.setIsOptionChecked("Stereo", false);
HMD.ipdScale = 0.0;
}
}
function scriptEnding() {
Menu.removeMenuItem("Tools > IPD", "Stereo");
Menu.removeMenuItem("Tools > IPD", "Mono");
Menu.removeMenu("Tools > IPD");
//reset the HMD to stereo mode
HMD.setIPDScale(1.0);
}
setupipdMenu();
Menu.menuItemEvent.connect(menuItemEvent);
Script.scriptEnding.connect(scriptEnding);

View file

@ -12,6 +12,7 @@
#include <avatar/AvatarActionHold.h>
#include <avatar/AvatarActionKinematicHold.h>
#include <ObjectActionOffset.h>
#include <ObjectActionSpring.h>
@ -28,6 +29,8 @@ EntityActionPointer interfaceActionFactory(EntityActionType type, const QUuid& i
return (EntityActionPointer) new ObjectActionSpring(id, ownerEntity);
case ACTION_TYPE_HOLD:
return (EntityActionPointer) new AvatarActionHold(id, ownerEntity);
case ACTION_TYPE_KINEMATIC_HOLD:
return (EntityActionPointer) new AvatarActionKinematicHold(id, ownerEntity);
}
assert(false);
@ -65,9 +68,9 @@ EntityActionPointer InterfaceActionFactory::factoryBA(EntityItemPointer ownerEnt
if (action) {
action->deserialize(data);
}
if (action->lifetimeIsOver()) {
return nullptr;
if (action->lifetimeIsOver()) {
return nullptr;
}
}
return action;

View file

@ -139,6 +139,10 @@ void PluginContainerProxy::unsetFullscreen(const QScreen* avoid) {
#endif
}
void PluginContainerProxy::requestReset() {
// We could signal qApp to sequence this, but it turns out that requestReset is only used from within the main thread anyway.
qApp->resetSensors();
}
void PluginContainerProxy::showDisplayPluginsTools() {
DependencyManager::get<DialogsManager>()->hmdTools(true);

View file

@ -16,10 +16,11 @@ class PluginContainerProxy : public QObject, PluginContainer {
virtual QAction* addMenuItem(const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override;
virtual void removeMenuItem(const QString& menuName, const QString& menuItem) override;
virtual bool isOptionChecked(const QString& name) override;
virtual void setIsOptionChecked(const QString& path, bool checked);
virtual void setIsOptionChecked(const QString& path, bool checked) override;
virtual void setFullscreen(const QScreen* targetScreen, bool hideMenu = true) override;
virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) override;
virtual void showDisplayPluginsTools() override;
virtual void requestReset() override;
virtual QGLWidget* getPrimarySurface() override;
virtual bool isForeground() override;
QRect _savedGeometry{ 10, 120, 800, 600 };

View file

@ -0,0 +1,188 @@
//
// AvatarActionKinematicHold.cpp
// interface/src/avatar/
//
// Created by Seth Alves 2015-6-9
// Copyright 2015 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 "QVariantGLM.h"
#include "avatar/MyAvatar.h"
#include "avatar/AvatarManager.h"
#include "AvatarActionKinematicHold.h"
const uint16_t AvatarActionKinematicHold::holdVersion = 1;
AvatarActionKinematicHold::AvatarActionKinematicHold(const QUuid& id, EntityItemPointer ownerEntity) :
ObjectActionSpring(id, ownerEntity),
_relativePosition(glm::vec3(0.0f)),
_relativeRotation(glm::quat()),
_hand("right"),
_mine(false),
_previousPositionalTarget(Vectors::ZERO),
_previousRotationalTarget(Quaternions::IDENTITY)
{
_type = ACTION_TYPE_KINEMATIC_HOLD;
#if WANT_DEBUG
qDebug() << "AvatarActionKinematicHold::AvatarActionKinematicHold";
#endif
}
AvatarActionKinematicHold::~AvatarActionKinematicHold() {
#if WANT_DEBUG
qDebug() << "AvatarActionKinematicHold::~AvatarActionKinematicHold";
#endif
}
void AvatarActionKinematicHold::updateActionWorker(float deltaTimeStep) {
if (!_mine) {
// if a local script isn't updating this, then we are just getting spring-action data over the wire.
// let the super-class handle it.
ObjectActionSpring::updateActionWorker(deltaTimeStep);
return;
}
assert(deltaTimeStep > 0.0f);
glm::quat rotation;
glm::vec3 position;
glm::vec3 offset;
bool gotLock = withTryReadLock([&]{
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
glm::vec3 palmPosition;
glm::quat palmRotation;
if (_hand == "right") {
palmPosition = myAvatar->getRightPalmPosition();
palmRotation = myAvatar->getRightPalmRotation();
} else {
palmPosition = myAvatar->getLeftPalmPosition();
palmRotation = myAvatar->getLeftPalmRotation();
}
rotation = palmRotation * _relativeRotation;
offset = rotation * _relativePosition;
position = palmPosition + offset;
});
if (gotLock) {
gotLock = withTryWriteLock([&]{
if (_positionalTarget != position || _rotationalTarget != rotation) {
_positionalTarget = position;
_rotationalTarget = rotation;
auto ownerEntity = _ownerEntity.lock();
if (ownerEntity) {
ownerEntity->setActionDataDirty(true);
void* physicsInfo = ownerEntity->getPhysicsInfo();
if (physicsInfo) {
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
btRigidBody* rigidBody = motionState ? motionState->getRigidBody() : nullptr;
if (!rigidBody) {
qDebug() << "ObjectActionSpring::updateActionWorker no rigidBody";
return;
}
if (_setVelocity) {
if (_previousSet) {
glm::vec3 positionalVelocity = (_positionalTarget - _previousPositionalTarget) / deltaTimeStep;
rigidBody->setLinearVelocity(glmToBullet(positionalVelocity));
// back up along velocity a bit in order to smooth out a "vibrating" appearance
_positionalTarget -= positionalVelocity * deltaTimeStep / 2.0f;
}
}
btTransform worldTrans = rigidBody->getWorldTransform();
worldTrans.setOrigin(glmToBullet(_positionalTarget));
worldTrans.setRotation(glmToBullet(_rotationalTarget));
rigidBody->setWorldTransform(worldTrans);
_previousPositionalTarget = _positionalTarget;
_previousRotationalTarget = _rotationalTarget;
_previousSet = true;
}
}
}
});
}
if (gotLock) {
ObjectActionSpring::updateActionWorker(deltaTimeStep);
}
}
bool AvatarActionKinematicHold::updateArguments(QVariantMap arguments) {
if (!ObjectAction::updateArguments(arguments)) {
return false;
}
bool ok = true;
glm::vec3 relativePosition =
EntityActionInterface::extractVec3Argument("kinematic-hold", arguments, "relativePosition", ok, false);
if (!ok) {
relativePosition = _relativePosition;
}
ok = true;
glm::quat relativeRotation =
EntityActionInterface::extractQuatArgument("kinematic-hold", arguments, "relativeRotation", ok, false);
if (!ok) {
relativeRotation = _relativeRotation;
}
ok = true;
QString hand =
EntityActionInterface::extractStringArgument("kinematic-hold", arguments, "hand", ok, false);
if (!ok || !(hand == "left" || hand == "right")) {
hand = _hand;
}
ok = true;
int setVelocity =
EntityActionInterface::extractIntegerArgument("kinematic-hold", arguments, "setVelocity", ok, false);
if (!ok) {
setVelocity = false;
}
if (relativePosition != _relativePosition
|| relativeRotation != _relativeRotation
|| hand != _hand) {
withWriteLock([&] {
_relativePosition = relativePosition;
_relativeRotation = relativeRotation;
_hand = hand;
_setVelocity = setVelocity;
_mine = true;
_active = true;
activateBody();
});
}
return true;
}
QVariantMap AvatarActionKinematicHold::getArguments() {
QVariantMap arguments = ObjectAction::getArguments();
withReadLock([&]{
if (!_mine) {
arguments = ObjectActionSpring::getArguments();
return;
}
arguments["relativePosition"] = glmToQMap(_relativePosition);
arguments["relativeRotation"] = glmToQMap(_relativeRotation);
arguments["setVelocity"] = _setVelocity;
arguments["hand"] = _hand;
});
return arguments;
}
void AvatarActionKinematicHold::deserialize(QByteArray serializedArguments) {
if (!_mine) {
ObjectActionSpring::deserialize(serializedArguments);
}
}

View file

@ -0,0 +1,47 @@
//
// AvatarActionKinematicHold.h
// interface/src/avatar/
//
// Created by Seth Alves 2015-10-2
// Copyright 2015 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_AvatarActionKinematicHold_h
#define hifi_AvatarActionKinematicHold_h
#include <QUuid>
#include <EntityItem.h>
#include <ObjectActionSpring.h>
class AvatarActionKinematicHold : public ObjectActionSpring {
public:
AvatarActionKinematicHold(const QUuid& id, EntityItemPointer ownerEntity);
virtual ~AvatarActionKinematicHold();
virtual bool updateArguments(QVariantMap arguments);
virtual QVariantMap getArguments();
virtual void updateActionWorker(float deltaTimeStep);
virtual void deserialize(QByteArray serializedArguments);
private:
static const uint16_t holdVersion;
glm::vec3 _relativePosition;
glm::quat _relativeRotation;
QString _hand;
bool _mine = false;
bool _previousSet = false;
glm::vec3 _previousPositionalTarget;
glm::quat _previousRotationalTarget;
bool _setVelocity = false;
};
#endif // hifi_AvatarActionKinematicHold_h

View file

@ -139,19 +139,19 @@ public:
void updateLookAtTargetAvatar();
void clearLookAtTargetAvatar();
virtual void setJointRotations(QVector<glm::quat> jointRotations);
virtual void setJointTranslations(QVector<glm::vec3> jointTranslations);
virtual void setJointData(int index, const glm::quat& rotation, const glm::vec3& translation);
virtual void setJointRotation(int index, const glm::quat& rotation);
virtual void setJointTranslation(int index, const glm::vec3& translation);
virtual void clearJointData(int index);
virtual void clearJointsData();
virtual void setJointRotations(QVector<glm::quat> jointRotations) override;
virtual void setJointTranslations(QVector<glm::vec3> jointTranslations) override;
virtual void setJointData(int index, const glm::quat& rotation, const glm::vec3& translation) override;
virtual void setJointRotation(int index, const glm::quat& rotation) override;
virtual void setJointTranslation(int index, const glm::vec3& translation) override;
virtual void clearJointData(int index) override;
virtual void clearJointsData() override;
Q_INVOKABLE void useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName = QString());
Q_INVOKABLE const QUrl& getFullAvatarURLFromPreferences() const { return _fullAvatarURLFromPreferences; }
Q_INVOKABLE const QString& getFullAvatarModelName() const { return _fullAvatarModelName; }
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData);
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData) override;
DynamicCharacterController* getCharacterController() { return &_characterController; }
@ -218,7 +218,7 @@ public slots:
void saveRecording(QString filename);
void loadLastRecording();
virtual void rebuildSkeletonBody();
virtual void rebuildSkeletonBody() override;
bool getEnableRigAnimations() const { return _rig->getEnableRig(); }
void setEnableRigAnimations(bool isEnabled);
@ -243,7 +243,7 @@ private:
glm::vec3 getWorldBodyPosition() const;
glm::quat getWorldBodyOrientation() const;
QByteArray toByteArray(bool cullSmallChanges, bool sendAll);
QByteArray toByteArray(bool cullSmallChanges, bool sendAll) override;
void simulate(float deltaTime);
void updateFromTrackers(float deltaTime);
virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPositio) override;
@ -252,9 +252,9 @@ private:
void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; }
bool getShouldRenderLocally() const { return _shouldRender; }
bool getDriveKeys(int key) { return _driveKeys[key] != 0.0f; };
bool isMyAvatar() const { return true; }
virtual int parseDataFromBuffer(const QByteArray& buffer);
virtual glm::vec3 getSkeletonPosition() const;
bool isMyAvatar() const override { return true; }
virtual int parseDataFromBuffer(const QByteArray& buffer) override;
virtual glm::vec3 getSkeletonPosition() const override;
glm::vec3 getScriptedMotorVelocity() const { return _scriptedMotorVelocity; }
float getScriptedMotorTimescale() const { return _scriptedMotorTimescale; }
@ -264,7 +264,7 @@ private:
void setScriptedMotorFrame(QString frame);
virtual void attach(const QString& modelURL, const QString& jointName = QString(),
const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(), float scale = 1.0f,
bool allowDuplicates = false, bool useSaved = true);
bool allowDuplicates = false, bool useSaved = true) override;
void renderLaserPointers(gpu::Batch& batch);
const RecorderPointer getRecorder() const { return _recorder; }
@ -273,8 +273,8 @@ private:
bool cameraInsideHead() const;
// These are made private for MyAvatar so that you will use the "use" methods instead
virtual void setFaceModelURL(const QUrl& faceModelURL);
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
virtual void setFaceModelURL(const QUrl& faceModelURL) override;
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override;
void setVisibleInSceneIfReady(Model* model, render::ScenePointer scene, bool visiblity);

View file

@ -27,10 +27,10 @@ public:
SkeletonModel(Avatar* owningAvatar, QObject* parent = nullptr, RigPointer rig = nullptr);
~SkeletonModel();
virtual void initJointStates(QVector<JointState> states);
virtual void initJointStates(QVector<JointState> states) override;
virtual void simulate(float deltaTime, bool fullUpdate = true);
virtual void updateRig(float deltaTime, glm::mat4 parentTransform);
virtual void simulate(float deltaTime, bool fullUpdate = true) override;
virtual void updateRig(float deltaTime, glm::mat4 parentTransform) override;
void updateAttitude();
void renderIKConstraints(gpu::Batch& batch);

View file

@ -159,7 +159,7 @@ void AnimClip::copyFromNetworkAnim() {
// used to adjust translation offsets, so large translation animatons on the reference skeleton
// will be adjusted when played on a skeleton with short limbs.
float limbLengthScale = fabs(glm::length(fbxZeroTrans)) <= 0.0001f ? 1.0f : (glm::length(relBindPose.trans) / glm::length(fbxZeroTrans));
float limbLengthScale = fabsf(glm::length(fbxZeroTrans)) <= 0.0001f ? 1.0f : (glm::length(relBindPose.trans) / glm::length(fbxZeroTrans));
AnimPose& pose = _anim[frame][skeletonJoint];
const FBXAnimationFrame& fbxAnimFrame = geom.animationFrames[frame];

View file

@ -52,7 +52,7 @@ protected:
void computeTargets(const AnimVariantMap& animVars, std::vector<IKTarget>& targets, const AnimPoseVec& underPoses);
void solveWithCyclicCoordinateDescent(const std::vector<IKTarget>& targets);
virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton);
virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) override;
// for AnimDebugDraw rendering
virtual const AnimPoseVec& getPosesInternal() const override { return _relativePoses; }

View file

@ -56,7 +56,7 @@ void RenderableBoxEntityItem::render(RenderArgs* args) {
if (_procedural->ready()) {
batch.setModelTransform(getTransformToCenter()); // we want to include the scale as well
_procedural->prepare(batch, this->getDimensions());
_procedural->prepare(batch, getPosition(), getDimensions());
auto color = _procedural->getColor(cubeColor);
batch._glColor4f(color.r, color.g, color.b, color.a);
DependencyManager::get<GeometryCache>()->renderCube(batch);

View file

@ -25,8 +25,8 @@ public:
void updateRenderItem();
virtual bool addToScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges);
virtual void removeFromScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges);
virtual bool addToScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges) override;
virtual void removeFromScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges) override;
protected:
render::ItemID _renderItemId;

View file

@ -62,7 +62,7 @@ void RenderableSphereEntityItem::render(RenderArgs* args) {
modelTransform.postScale(SPHERE_ENTITY_SCALE);
if (_procedural->ready()) {
batch.setModelTransform(modelTransform); // use a transform with scale, rotation, registration point and translation
_procedural->prepare(batch, getDimensions());
_procedural->prepare(batch, getPosition(), getDimensions());
auto color = _procedural->getColor(sphereColor);
batch._glColor4f(color.r, color.g, color.b, color.a);
DependencyManager::get<GeometryCache>()->renderSphere(batch);

View file

@ -100,6 +100,9 @@ EntityActionType EntityActionInterface::actionTypeFromString(QString actionTypeS
if (normalizedActionTypeString == "hold") {
return ACTION_TYPE_HOLD;
}
if (normalizedActionTypeString == "kinematichold") {
return ACTION_TYPE_KINEMATIC_HOLD;
}
qDebug() << "Warning -- EntityActionInterface::actionTypeFromString got unknown action-type name" << actionTypeString;
return ACTION_TYPE_NONE;
@ -115,6 +118,8 @@ QString EntityActionInterface::actionTypeToString(EntityActionType actionType) {
return "spring";
case ACTION_TYPE_HOLD:
return "hold";
case ACTION_TYPE_KINEMATIC_HOLD:
return "kinematic-hold";
}
assert(false);
return "none";
@ -244,6 +249,28 @@ float EntityActionInterface::extractFloatArgument(QString objectName, QVariantMa
return v;
}
int EntityActionInterface::extractIntegerArgument(QString objectName, QVariantMap arguments,
QString argumentName, bool& ok, bool required) {
if (!arguments.contains(argumentName)) {
if (required) {
qDebug() << objectName << "requires argument:" << argumentName;
}
ok = false;
return 0.0f;
}
QVariant vV = arguments[argumentName];
bool vOk = true;
int v = vV.toInt(&vOk);
if (!vOk || v != v) {
ok = false;
return 0;
}
return v;
}
QString EntityActionInterface::extractStringArgument(QString objectName, QVariantMap arguments,
QString argumentName, bool& ok, bool required) {
if (!arguments.contains(argumentName)) {

View file

@ -23,7 +23,8 @@ enum EntityActionType {
ACTION_TYPE_NONE = 0,
ACTION_TYPE_OFFSET = 1000,
ACTION_TYPE_SPRING = 2000,
ACTION_TYPE_HOLD = 3000
ACTION_TYPE_HOLD = 3000,
ACTION_TYPE_KINEMATIC_HOLD = 4000
};
@ -48,6 +49,8 @@ public:
virtual bool lifetimeIsOver() { return false; }
bool locallyAddedButNotYetReceived = false;
protected:
virtual glm::vec3 getPosition() = 0;
virtual void setPosition(glm::vec3 position) = 0;
@ -67,6 +70,8 @@ protected:
QString argumentName, bool& ok, bool required = true);
static float extractFloatArgument(QString objectName, QVariantMap arguments,
QString argumentName, bool& ok, bool required = true);
static int extractIntegerArgument(QString objectName, QVariantMap arguments,
QString argumentName, bool& ok, bool required = true);
static QString extractStringArgument(QString objectName, QVariantMap arguments,
QString argumentName, bool& ok, bool required = true);

View file

@ -34,6 +34,7 @@
bool EntityItem::_sendPhysicsUpdates = true;
int EntityItem::_maxActionsDataSize = 800;
quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND;
EntityItem::EntityItem(const EntityItemID& entityItemID) :
_type(EntityTypes::Unknown),
@ -1505,6 +1506,8 @@ bool EntityItem::addAction(EntitySimulation* simulation, EntityActionPointer act
result = addActionInternal(simulation, action);
if (!result) {
removeActionInternal(action->getID());
} else {
action->locallyAddedButNotYetReceived = true;
}
});
@ -1525,7 +1528,8 @@ bool EntityItem::addActionInternal(EntitySimulation* simulation, EntityActionPoi
simulation->addAction(action);
bool success;
QByteArray newDataCache = serializeActions(success);
QByteArray newDataCache;
serializeActions(success, newDataCache);
if (success) {
_allActionsDataCache = newDataCache;
_dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION;
@ -1546,7 +1550,7 @@ bool EntityItem::updateAction(EntitySimulation* simulation, const QUuid& actionI
success = action->updateArguments(arguments);
if (success) {
_allActionsDataCache = serializeActions(success);
serializeActions(success, _allActionsDataCache);
_dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION;
} else {
qDebug() << "EntityItem::updateAction failed";
@ -1566,6 +1570,7 @@ bool EntityItem::removeAction(EntitySimulation* simulation, const QUuid& actionI
bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulation* simulation) {
assertWriteLocked();
_previouslyDeletedActions.insert(actionID, usecTimestampNow());
if (_objectActions.contains(actionID)) {
if (!simulation) {
EntityTreePointer entityTree = _element ? _element->getTree() : nullptr;
@ -1581,7 +1586,7 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulation* s
}
bool success = true;
_allActionsDataCache = serializeActions(success);
serializeActions(success, _allActionsDataCache);
_dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION;
return success;
}
@ -1618,6 +1623,8 @@ void EntityItem::deserializeActions() {
void EntityItem::deserializeActionsInternal() {
assertWriteLocked();
quint64 now = usecTimestampNow();
if (!_element) {
return;
}
@ -1643,6 +1650,10 @@ void EntityItem::deserializeActionsInternal() {
QUuid actionID;
serializedActionStream >> actionType;
serializedActionStream >> actionID;
if (_previouslyDeletedActions.contains(actionID)) {
continue;
}
updated << actionID;
if (_objectActions.contains(actionID)) {
@ -1650,14 +1661,14 @@ void EntityItem::deserializeActionsInternal() {
// TODO: make sure types match? there isn't currently a way to
// change the type of an existing action.
action->deserialize(serializedAction);
action->locallyAddedButNotYetReceived = false;
} else {
auto actionFactory = DependencyManager::get<EntityActionFactoryInterface>();
// EntityItemPointer entity = entityTree->findEntityByEntityItemID(_id, false);
EntityItemPointer entity = shared_from_this();
EntityActionPointer action = actionFactory->factoryBA(entity, serializedAction);
if (action) {
entity->addActionInternal(simulation, action);
action->locallyAddedButNotYetReceived = false;
}
}
}
@ -1667,11 +1678,27 @@ void EntityItem::deserializeActionsInternal() {
while (i != _objectActions.end()) {
QUuid id = i.key();
if (!updated.contains(id)) {
_actionsToRemove << id;
EntityActionPointer action = i.value();
// if we've just added this action, don't remove it due to lack of mention in an incoming packet.
if (! action->locallyAddedButNotYetReceived) {
_actionsToRemove << id;
_previouslyDeletedActions.insert(id, now);
}
}
i++;
}
// trim down _previouslyDeletedActions
QMutableHashIterator<QUuid, quint64> _previouslyDeletedIter(_previouslyDeletedActions);
while (_previouslyDeletedIter.hasNext()) {
_previouslyDeletedIter.next();
if (now - _previouslyDeletedIter.value() > _rememberDeletedActionTime) {
_previouslyDeletedActions.remove(_previouslyDeletedIter.key());
}
}
_actionDataDirty = true;
return;
}
@ -1697,13 +1724,13 @@ void EntityItem::setActionDataInternal(QByteArray actionData) {
deserializeActionsInternal();
}
QByteArray EntityItem::serializeActions(bool& success) const {
void EntityItem::serializeActions(bool& success, QByteArray& result) const {
assertLocked();
QByteArray result;
if (_objectActions.size() == 0) {
success = true;
return QByteArray();
result.clear();
return;
}
QVector<QByteArray> serializedActions;
@ -1721,21 +1748,20 @@ QByteArray EntityItem::serializeActions(bool& success) const {
if (result.size() >= _maxActionsDataSize) {
success = false;
return result;
return;
}
success = true;
return result;
return;
}
const QByteArray EntityItem::getActionDataInternal() const {
if (_actionDataDirty) {
bool success;
QByteArray newDataCache = serializeActions(success);
serializeActions(success, _allActionsDataCache);
if (success) {
_allActionsDataCache = newDataCache;
_actionDataDirty = false;
}
_actionDataDirty = false;
}
return _allActionsDataCache;
}

View file

@ -508,17 +508,21 @@ protected:
bool addActionInternal(EntitySimulation* simulation, EntityActionPointer action);
bool removeActionInternal(const QUuid& actionID, EntitySimulation* simulation = nullptr);
void deserializeActionsInternal();
QByteArray serializeActions(bool& success) const;
void serializeActions(bool& success, QByteArray& result) const;
QHash<QUuid, EntityActionPointer> _objectActions;
static int _maxActionsDataSize;
mutable QByteArray _allActionsDataCache;
// when an entity-server starts up, EntityItem::setActionData is called before the entity-tree is
// ready. This means we can't find our EntityItemPointer or add the action to the simulation. These
// are used to keep track of and work around this situation.
void checkWaitingToRemove(EntitySimulation* simulation = nullptr);
mutable QSet<QUuid> _actionsToRemove;
mutable bool _actionDataDirty = false;
// _previouslyDeletedActions is used to avoid an action being re-added due to server round-trip lag
static quint64 _rememberDeletedActionTime;
mutable QHash<QUuid, quint64> _previouslyDeletedActions;
};
#endif // hifi_EntityItem_h

View file

@ -156,24 +156,24 @@ public:
// Indirect buffer is used by the multiDrawXXXIndirect calls
// The indirect buffer contains the command descriptions to execute multiple drawcalls in a single call
void setIndirectBuffer(const BufferPointer& buffer, Offset offset = 0, Offset stride = 0);
// multi command desctription for multiDrawIndexedIndirect
class DrawIndirectCommand {
public:
uint _count{ 0 };
uint _instanceCount{ 0 };
uint _firstIndex{ 0 };
uint _baseInstance{ 0 };
// multi command desctription for multiDrawIndexedIndirect
class DrawIndirectCommand {
public:
uint _count{ 0 };
uint _instanceCount{ 0 };
uint _firstIndex{ 0 };
uint _baseInstance{ 0 };
};
// multi command desctription for multiDrawIndexedIndirect
class DrawIndexedIndirectCommand {
public:
uint _count{ 0 };
uint _instanceCount{ 0 };
uint _firstIndex{ 0 };
uint _baseVertex{ 0 };
uint _baseInstance{ 0 };
// multi command desctription for multiDrawIndexedIndirect
class DrawIndexedIndirectCommand {
public:
uint _count{ 0 };
uint _instanceCount{ 0 };
uint _firstIndex{ 0 };
uint _baseVertex{ 0 };
uint _baseInstance{ 0 };
};
// Transform Stage
@ -246,6 +246,26 @@ public:
void _glUniform4iv(int location, int count, const int* value);
void _glUniformMatrix4fv(int location, int count, unsigned char transpose, const float* value);
void _glUniform(int location, int v0) {
_glUniform1i(location, v0);
}
void _glUniform(int location, float v0) {
_glUniform1f(location, v0);
}
void _glUniform(int location, const glm::vec2& v) {
_glUniform2f(location, v.x, v.y);
}
void _glUniform(int location, const glm::vec3& v) {
_glUniform3f(location, v.x, v.y, v.z);
}
void _glUniform(int location, const glm::vec4& v) {
_glUniform4f(location, v.x, v.y, v.z, v.w);
}
void _glColor4f(float red, float green, float blue, float alpha);
enum Command {

View file

@ -343,9 +343,22 @@ bool Texture::assignStoredMipFace(uint16 level, const Element& format, Size size
}
uint16 Texture::autoGenerateMips(uint16 maxMip) {
_autoGenerateMips = true;
_maxMip = std::min((uint16) (evalNumMips() - 1), maxMip);
_stamp++;
bool changed = false;
if (!_autoGenerateMips) {
changed = true;
_autoGenerateMips = true;
}
auto newMaxMip = std::min((uint16)(evalNumMips() - 1), maxMip);
if (newMaxMip != _maxMip) {
changed = true;
_maxMip = newMaxMip;;
}
if (changed) {
_stamp++;
}
return _maxMip;
}

View file

@ -59,7 +59,7 @@ public:
// Plugin functions
virtual bool isSupported() const override { return true; }
virtual bool isJointController() const override { return false; }
const QString& getName() const { return NAME; }
const QString& getName() const override { return NAME; }
virtual void activate() override {};
virtual void deactivate() override {};

View file

@ -30,7 +30,7 @@ public:
// Plugin functions
virtual bool isSupported() const override;
virtual bool isJointController() const override { return false; }
const QString& getName() const { return NAME; }
const QString& getName() const override { return NAME; }
virtual void init() override;
virtual void deinit() override;

View file

@ -285,6 +285,7 @@ void SixenseManager::updateCalibration(void* controllersX) {
_avatarRotation = glm::inverse(glm::quat_cast(glm::mat3(xAxis, Vectors::UNIT_Y, zAxis)));
const float Y_OFFSET_CALIBRATED_HANDS_TO_AVATAR = -0.3f;
_avatarPosition.y += Y_OFFSET_CALIBRATED_HANDS_TO_AVATAR;
CONTAINER->requestReset();
qCDebug(inputplugins, "succeess: sixense calibration");
}
break;

View file

@ -63,7 +63,7 @@ public:
// Plugin functions
virtual bool isSupported() const override;
virtual bool isJointController() const override { return true; }
const QString& getName() const { return NAME; }
const QString& getName() const override { return NAME; }
virtual void activate() override;
virtual void deactivate() override;

View file

@ -53,7 +53,7 @@ public:
// Plugin functions
virtual bool isSupported() const override;
virtual bool isJointController() const override { return true; }
const QString& getName() const { return NAME; }
const QString& getName() const override { return NAME; }
virtual void activate() override;
virtual void deactivate() override;

View file

@ -7,5 +7,5 @@ add_dependency_external_projects(glm)
find_package(GLM REQUIRED)
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
link_hifi_libraries(shared networking gpu model)
link_hifi_libraries(shared networking gpu model fbx)

View file

@ -30,9 +30,9 @@ class OctreeHeadlessViewer : public OctreeRenderer {
public:
OctreeHeadlessViewer();
virtual ~OctreeHeadlessViewer() {};
virtual void renderElement(OctreeElementPointer element, RenderArgs* args) { /* swallow these */ }
virtual void renderElement(OctreeElementPointer element, RenderArgs* args) override { /* swallow these */ }
virtual void init();
virtual void init() override ;
virtual void render(RenderArgs* renderArgs) override { /* swallow these */ }
void setJurisdictionListener(JurisdictionListener* jurisdictionListener) { _jurisdictionListener = jurisdictionListener; }
@ -58,7 +58,7 @@ public slots:
// getters for LOD and PPS
float getVoxelSizeScale() const { return _voxelSizeScale; }
int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; }
int getBoundaryLevelAdjust() const override { return _boundaryLevelAdjust; }
int getMaxPacketsPerSecond() const { return _maxPacketsPerSecond; }
unsigned getOctreeElementsCount() const { return _tree->getOctreeElementsCount(); }

View file

@ -26,6 +26,7 @@ public:
virtual void setFullscreen(const QScreen* targetScreen, bool hideMenu = false) = 0;
virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) = 0;
virtual void showDisplayPluginsTools() = 0;
virtual void requestReset() = 0;
virtual QGLWidget* getPrimarySurface() = 0;
virtual bool isForeground() = 0;
};

View file

@ -17,20 +17,30 @@
#include <gpu/Batch.h>
#include <SharedUtil.h>
#include <NumericalConstants.h>
#include <GLMHelpers.h>
#include "ProceduralShaders.h"
static const char* const UNIFORM_TIME_NAME= "iGlobalTime";
static const char* const UNIFORM_SCALE_NAME = "iWorldScale";
// Userdata parsing constants
static const QString PROCEDURAL_USER_DATA_KEY = "ProceduralEntity";
static const QString URL_KEY = "shaderUrl";
static const QString VERSION_KEY = "version";
static const QString UNIFORMS_KEY = "uniforms";
static const QString CHANNELS_KEY = "channels";
// Shader replace strings
static const std::string PROCEDURAL_BLOCK = "//PROCEDURAL_BLOCK";
static const std::string PROCEDURAL_COMMON_BLOCK = "//PROCEDURAL_COMMON_BLOCK";
static const std::string PROCEDURAL_VERSION = "//PROCEDURAL_VERSION";
static const std::string STANDARD_UNIFORM_NAMES[Procedural::NUM_STANDARD_UNIFORMS] = {
"iDate",
"iGlobalTime",
"iFrameCount",
"iWorldScale",
"iWorldPosition",
"iChannelResolution"
};
// Example
//{
@ -100,7 +110,21 @@ void Procedural::parse(const QJsonObject& proceduralData) {
{
auto uniforms = proceduralData[UNIFORMS_KEY];
if (uniforms.isObject()) {
_uniforms = uniforms.toObject();;
_parsedUniforms = uniforms.toObject();
}
}
// Grab any textures
{
auto channels = proceduralData[CHANNELS_KEY];
if (channels.isArray()) {
auto textureCache = DependencyManager::get<TextureCache>();
_parsedChannels = channels.toArray();
size_t channelCount = std::min(MAX_PROCEDURAL_TEXTURE_CHANNELS, (size_t)_parsedChannels.size());
for (size_t i = 0; i < channelCount; ++i) {
QString url = _parsedChannels.at(i).toString();
_channels[i] = textureCache->getTexture(QUrl(url));
}
}
}
_enabled = true;
@ -111,20 +135,26 @@ bool Procedural::ready() {
return false;
}
if (!_shaderPath.isEmpty()) {
return true;
// Do we have a network or local shader
if (_shaderPath.isEmpty() && (!_networkShader || !_networkShader->isLoaded())) {
return false;
}
if (_networkShader) {
return _networkShader->isLoaded();
// Do we have textures, and if so, are they loaded?
for (size_t i = 0; i < MAX_PROCEDURAL_TEXTURE_CHANNELS; ++i) {
if (_channels[i] && !_channels[i]->isLoaded()) {
return false;
}
}
return false;
return true;
}
void Procedural::prepare(gpu::Batch& batch, const glm::vec3& size) {
void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size) {
_entityDimensions = size;
_entityPosition = position;
if (_shaderUrl.isLocalFile()) {
auto lastModified = (quint64) QFileInfo(_shaderPath).lastModified().toMSecsSinceEpoch();
auto lastModified = (quint64)QFileInfo(_shaderPath).lastModified().toMSecsSinceEpoch();
if (lastModified > _shaderModified) {
QFile file(_shaderPath);
file.open(QIODevice::ReadOnly);
@ -164,69 +194,183 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& size) {
//qDebug() << "FragmentShader:\n" << fragmentShaderSource.c_str();
_fragmentShader = gpu::ShaderPointer(gpu::Shader::createPixel(fragmentShaderSource));
_shader = gpu::ShaderPointer(gpu::Shader::createProgram(_vertexShader, _fragmentShader));
gpu::Shader::makeProgram(*_shader);
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("iChannel0"), 0));
slotBindings.insert(gpu::Shader::Binding(std::string("iChannel1"), 1));
slotBindings.insert(gpu::Shader::Binding(std::string("iChannel2"), 2));
slotBindings.insert(gpu::Shader::Binding(std::string("iChannel3"), 3));
gpu::Shader::makeProgram(*_shader, slotBindings);
_pipeline = gpu::PipelinePointer(gpu::Pipeline::create(_shader, _state));
_timeSlot = _shader->getUniforms().findLocation(UNIFORM_TIME_NAME);
_scaleSlot = _shader->getUniforms().findLocation(UNIFORM_SCALE_NAME);
for (size_t i = 0; i < NUM_STANDARD_UNIFORMS; ++i) {
const std::string& name = STANDARD_UNIFORM_NAMES[i];
_standardUniformSlots[i] = _shader->getUniforms().findLocation(name);
}
_start = usecTimestampNow();
_frameCount = 0;
}
batch.setPipeline(_pipeline);
if (_pipelineDirty) {
_pipelineDirty = false;
// Set any userdata specified uniforms
foreach(QString key, _uniforms.keys()) {
std::string uniformName = key.toLocal8Bit().data();
int32_t slot = _shader->getUniforms().findLocation(uniformName);
if (gpu::Shader::INVALID_LOCATION == slot) {
continue;
setupUniforms();
}
for (auto lambda : _uniforms) {
lambda(batch);
}
static gpu::Sampler sampler;
static std::once_flag once;
std::call_once(once, [&] {
gpu::Sampler::Desc desc;
desc._filter = gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR;
});
for (size_t i = 0; i < MAX_PROCEDURAL_TEXTURE_CHANNELS; ++i) {
if (_channels[i] && _channels[i]->isLoaded()) {
auto gpuTexture = _channels[i]->getGPUTexture();
if (gpuTexture) {
gpuTexture->setSampler(sampler);
gpuTexture->autoGenerateMips(-1);
}
QJsonValue value = _uniforms[key];
if (value.isDouble()) {
batch._glUniform1f(slot, value.toDouble());
} else if (value.isArray()) {
auto valueArray = value.toArray();
switch (valueArray.size()) {
case 0:
break;
batch.setResourceTexture(i, gpuTexture);
}
}
}
case 1:
batch._glUniform1f(slot, valueArray[0].toDouble());
break;
case 2:
batch._glUniform2f(slot,
valueArray[0].toDouble(),
valueArray[1].toDouble());
break;
case 3:
batch._glUniform3f(slot,
valueArray[0].toDouble(),
valueArray[1].toDouble(),
valueArray[2].toDouble());
break;
case 4:
default:
batch._glUniform4f(slot,
valueArray[0].toDouble(),
valueArray[1].toDouble(),
valueArray[2].toDouble(),
valueArray[3].toDouble());
break;
void Procedural::setupUniforms() {
_uniforms.clear();
// Set any userdata specified uniforms
foreach(QString key, _parsedUniforms.keys()) {
std::string uniformName = key.toLocal8Bit().data();
int32_t slot = _shader->getUniforms().findLocation(uniformName);
if (gpu::Shader::INVALID_LOCATION == slot) {
continue;
}
QJsonValue value = _parsedUniforms[key];
if (value.isDouble()) {
float v = value.toDouble();
_uniforms.push_back([=](gpu::Batch& batch) {
batch._glUniform1f(slot, v);
});
} else if (value.isArray()) {
auto valueArray = value.toArray();
switch (valueArray.size()) {
case 0:
break;
case 1: {
float v = valueArray[0].toDouble();
_uniforms.push_back([=](gpu::Batch& batch) {
batch._glUniform1f(slot, v);
});
break;
}
case 2: {
glm::vec2 v{ valueArray[0].toDouble(), valueArray[1].toDouble() };
_uniforms.push_back([=](gpu::Batch& batch) {
batch._glUniform2f(slot, v.x, v.y);
});
break;
}
case 3: {
glm::vec3 v{
valueArray[0].toDouble(),
valueArray[1].toDouble(),
valueArray[2].toDouble(),
};
_uniforms.push_back([=](gpu::Batch& batch) {
batch._glUniform3f(slot, v.x, v.y, v.z);
});
break;
}
default:
case 4: {
glm::vec4 v{
valueArray[0].toDouble(),
valueArray[1].toDouble(),
valueArray[2].toDouble(),
valueArray[3].toDouble(),
};
_uniforms.push_back([=](gpu::Batch& batch) {
batch._glUniform4f(slot, v.x, v.y, v.z, v.w);
});
break;
}
valueArray.size();
}
}
}
// Minimize floating point error by doing an integer division to milliseconds, before the floating point division to seconds
float time = (float)((usecTimestampNow() - _start) / USECS_PER_MSEC) / MSECS_PER_SECOND;
batch._glUniform1f(_timeSlot, time);
// FIXME move into the 'set once' section, since this doesn't change over time
batch._glUniform3f(_scaleSlot, size.x, size.y, size.z);
}
if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[TIME]) {
_uniforms.push_back([=](gpu::Batch& batch) {
// Minimize floating point error by doing an integer division to milliseconds, before the floating point division to seconds
float time = (float)((usecTimestampNow() - _start) / USECS_PER_MSEC) / MSECS_PER_SECOND;
batch._glUniform(_standardUniformSlots[TIME], time);
});
}
if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[DATE]) {
_uniforms.push_back([=](gpu::Batch& batch) {
QDateTime now = QDateTime::currentDateTimeUtc();
QDate date = now.date();
QTime time = now.time();
vec4 v;
v.x = date.year();
// Shadertoy month is 0 based
v.y = date.month() - 1;
// But not the day... go figure
v.z = date.day();
v.w = (time.hour() * 3600) + (time.minute() * 60) + time.second();
batch._glUniform(_standardUniformSlots[DATE], v);
});
}
if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[FRAME_COUNT]) {
_uniforms.push_back([=](gpu::Batch& batch) {
batch._glUniform(_standardUniformSlots[FRAME_COUNT], ++_frameCount);
});
}
if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[SCALE]) {
// FIXME move into the 'set once' section, since this doesn't change over time
_uniforms.push_back([=](gpu::Batch& batch) {
batch._glUniform(_standardUniformSlots[SCALE], _entityDimensions);
});
}
if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[SCALE]) {
// FIXME move into the 'set once' section, since this doesn't change over time
_uniforms.push_back([=](gpu::Batch& batch) {
batch._glUniform(_standardUniformSlots[SCALE], _entityDimensions);
});
}
if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[POSITION]) {
// FIXME move into the 'set once' section, since this doesn't change over time
_uniforms.push_back([=](gpu::Batch& batch) {
batch._glUniform(_standardUniformSlots[POSITION], _entityPosition);
});
}
if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[CHANNEL_RESOLUTION]) {
_uniforms.push_back([=](gpu::Batch& batch) {
vec3 channelSizes[MAX_PROCEDURAL_TEXTURE_CHANNELS];
for (size_t i = 0; i < MAX_PROCEDURAL_TEXTURE_CHANNELS; ++i) {
if (_channels[i]) {
channelSizes[i] = vec3(_channels[i]->getWidth(), _channels[i]->getHeight(), 1.0);
}
}
batch._glUniform3fv(_standardUniformSlots[CHANNEL_RESOLUTION], MAX_PROCEDURAL_TEXTURE_CHANNELS, &channelSizes[0].x);
});
}
}
glm::vec4 Procedural::getColor(const glm::vec4& entityColor) {
if (_version == 1) {

View file

@ -14,11 +14,16 @@
#include <QtCore/QString>
#include <QtCore/QUrl>
#include <QtCore/QJsonObject>
#include <QtCore/QJsonArray>
#include <gpu/Shader.h>
#include <gpu/Pipeline.h>
#include <gpu/Batch.h>
#include <model-networking/ShaderCache.h>
#include <model-networking/TextureCache.h>
using UniformLambdas = std::list<std::function<void(gpu::Batch& batch)>>;
const size_t MAX_PROCEDURAL_TEXTURE_CHANNELS{ 4 };
// FIXME better encapsulation
// FIXME better mechanism for extending to things rendered using shaders other than simple.slv
@ -29,7 +34,8 @@ struct Procedural {
void parse(const QString& userDataJson);
void parse(const QJsonObject&);
bool ready();
void prepare(gpu::Batch& batch, const glm::vec3& size);
void prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size);
void setupUniforms();
glm::vec4 getColor(const glm::vec4& entityColor);
bool _enabled{ false };
@ -43,17 +49,34 @@ struct Procedural {
QUrl _shaderUrl;
quint64 _shaderModified{ 0 };
bool _pipelineDirty{ true };
int32_t _timeSlot{ gpu::Shader::INVALID_LOCATION };
int32_t _scaleSlot{ gpu::Shader::INVALID_LOCATION };
uint64_t _start{ 0 };
NetworkShaderPointer _networkShader;
QJsonObject _uniforms;
enum StandardUniforms {
DATE,
TIME,
FRAME_COUNT,
SCALE,
POSITION,
CHANNEL_RESOLUTION,
NUM_STANDARD_UNIFORMS
};
int32_t _standardUniformSlots[NUM_STANDARD_UNIFORMS];
uint64_t _start{ 0 };
int32_t _frameCount{ 0 };
NetworkShaderPointer _networkShader;
QJsonObject _parsedUniforms;
QJsonArray _parsedChannels;
UniformLambdas _uniforms;
NetworkTexturePointer _channels[MAX_PROCEDURAL_TEXTURE_CHANNELS];
gpu::PipelinePointer _pipeline;
gpu::ShaderPointer _vertexShader;
gpu::ShaderPointer _fragmentShader;
gpu::ShaderPointer _shader;
gpu::StatePointer _state;
glm::vec3 _entityDimensions;
glm::vec3 _entityPosition;
};
#endif

View file

@ -262,15 +262,39 @@ float snoise(vec2 v) {
return 130.0 * dot(m, g);
}
// TODO add more uniforms
uniform float iGlobalTime; // shader playback time (in seconds)
uniform vec3 iWorldScale; // the dimensions of the object being rendered
// TODO add support for textures
// TODO document available inputs other than the uniforms
// TODO provide world scale in addition to the untransformed position
// shader playback time (in seconds)
uniform float iGlobalTime;
// the dimensions of the object being rendered
uniform vec3 iWorldScale;
#define PROCEDURAL 1
//PROCEDURAL_VERSION
#ifdef PROCEDURAL_V1
#else
// Unimplemented uniforms
// Resolution doesn't make sense in the VR context
const vec3 iResolution = vec3(1.0);
// Mouse functions not enabled currently
const vec4 iMouse = vec4(0.0);
// No support for audio input
const float iSampleRate = 1.0;
// No support for video input
const vec4 iChannelTime = vec4(0.0);
uniform vec4 iDate;
uniform int iFrameCount;
uniform vec3 iWorldPosition;
uniform vec3 iChannelResolution[4];
uniform sampler2D iChannel0;
uniform sampler2D iChannel1;
uniform sampler2D iChannel2;
uniform sampler2D iChannel3;
#endif
)SHADER";

View file

@ -1,20 +1,20 @@
//
// ProceduralSkybox.cpp
// libraries/procedural/src/procedural
//
// Created by Sam Gateau on 9/21/2015.
// Copyright 2015 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 "ProceduralSkybox.h"
#include <gpu/Batch.h>
#include <gpu/Context.h>
#include <ViewFrustum.h>
//
// ProceduralSkybox.cpp
// libraries/procedural/src/procedural
//
// Created by Sam Gateau on 9/21/2015.
// Copyright 2015 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 "ProceduralSkybox.h"
#include <gpu/Batch.h>
#include <gpu/Context.h>
#include <ViewFrustum.h>
#include "ProceduralSkybox_vert.h"
#include "ProceduralSkybox_frag.h"
@ -74,7 +74,7 @@ void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum,
batch.setResourceTexture(0, skybox.getCubemap());
}
skybox._procedural->prepare(batch, glm::vec3(1));
skybox._procedural->prepare(batch, glm::vec3(0), glm::vec3(1));
batch.draw(gpu::TRIANGLE_STRIP, 4);
}
}

View file

@ -120,11 +120,11 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont
}
// log prefix is in the following format
// [DEBUG] [TIMESTAMP] [PID] [TARGET] logged string
// [TIMESTAMP] [DEBUG] [PID] [TARGET] logged string
QString prefixString = QString("[%1]").arg(stringForLogType(type));
QString prefixString = QString("[%1]").arg(QDateTime::currentDateTime().toString(DATE_STRING_FORMAT));
prefixString.append(QString(" [%1]").arg(QDateTime::currentDateTime().toString(DATE_STRING_FORMAT)));
prefixString.append(QString(" [%1]").arg(stringForLogType(type)));
if (_shouldOutputPID) {
prefixString.append(QString(" [%1]").arg(QCoreApplication::instance()->applicationPid()));

View file

@ -260,7 +260,7 @@ protected:
}
void keyPressEvent(QKeyEvent* event) {
void keyPressEvent(QKeyEvent* event) override {
_altPressed = Qt::Key_Alt == event->key();
switch (event->key()) {
case Qt::Key_B:
@ -292,13 +292,13 @@ protected:
QWindow::keyPressEvent(event);
}
QQmlContext* menuContext{ nullptr };
void keyReleaseEvent(QKeyEvent *event) {
void keyReleaseEvent(QKeyEvent *event) override {
if (_altPressed && Qt::Key_Alt == event->key()) {
VrMenu::toggle();
}
}
void moveEvent(QMoveEvent* event) {
void moveEvent(QMoveEvent* event) override {
static qreal oldPixelRatio = 0.0;
if (devicePixelRatio() != oldPixelRatio) {
oldPixelRatio = devicePixelRatio();

View file

@ -71,13 +71,13 @@ function createAllToys() {
createCombinedArmChair({
x: 549.29,
y: 495.05,
y: 494.9,
z: 508.22
});
createPottedPlant({
x: 554.26,
y: 495.23,
y: 495.2,
z: 504.53
});
@ -98,7 +98,7 @@ function createAllToys() {
function deleteAllToys() {
var entities = Entities.findEntities(MyAvatar.position, 100);
entities.forEach(function (entity) {
entities.forEach(function(entity) {
//params: customKey, id, defaultValue
var shouldReset = getEntityCustomData(resetKey, entity, {}).resetMe;
if (shouldReset === true) {
@ -447,8 +447,7 @@ function createPingPongBallGun() {
var pingPongGun = Entities.addEntity({
type: "Model",
modelURL: MODEL_URL,
shapeType: 'compound',
compoundShapeURL: COLLISION_HULL_URL,
shapeType: 'box',
script: scriptURL,
position: position,
rotation: rotation,
@ -458,9 +457,9 @@ function createPingPongBallGun() {
z: 0
},
dimensions: {
x: 0.67,
y: 0.14,
z: 0.09
x: 0.08,
y: 0.21,
z: 0.47
},
collisionsWillMove: true,
});
@ -468,8 +467,6 @@ function createPingPongBallGun() {
setEntityCustomData(resetKey, pingPongGun, {
resetMe: true
});
}
function createBasketballHoop() {