Merge branch 'master' of https://github.com/worklist/hifi into more_edit_js
Conflicts: examples/editVoxels.js
|
@ -123,6 +123,30 @@ void broadcastIdentityPacket() {
|
|||
}
|
||||
}
|
||||
|
||||
void broadcastBillboardPacket(const SharedNodePointer& sendingNode) {
|
||||
AvatarMixerClientData* nodeData = static_cast<AvatarMixerClientData*>(sendingNode->getLinkedData());
|
||||
QByteArray packet = byteArrayWithPopulatedHeader(PacketTypeAvatarBillboard);
|
||||
packet.append(sendingNode->getUUID().toRfc4122());
|
||||
packet.append(nodeData->getBillboard());
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
||||
if (node->getType() == NodeType::Agent && node != sendingNode) {
|
||||
nodeList->writeDatagram(packet, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void broadcastBillboardPackets() {
|
||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
if (node->getLinkedData() && node->getType() == NodeType::Agent) {
|
||||
AvatarMixerClientData* nodeData = static_cast<AvatarMixerClientData*>(node->getLinkedData());
|
||||
broadcastBillboardPacket(node);
|
||||
nodeData->setHasSentBillboardBetweenKeyFrames(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarMixer::nodeKilled(SharedNodePointer killedNode) {
|
||||
if (killedNode->getType() == NodeType::Agent
|
||||
&& killedNode->getLinkedData()) {
|
||||
|
@ -170,6 +194,23 @@ void AvatarMixer::readPendingDatagrams() {
|
|||
nodeList->broadcastToNodes(identityPacket, NodeSet() << NodeType::Agent);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PacketTypeAvatarBillboard: {
|
||||
|
||||
// check if we have a matching node in our list
|
||||
SharedNodePointer avatarNode = nodeList->sendingNodeForPacket(receivedPacket);
|
||||
|
||||
if (avatarNode && avatarNode->getLinkedData()) {
|
||||
AvatarMixerClientData* nodeData = static_cast<AvatarMixerClientData*>(avatarNode->getLinkedData());
|
||||
if (nodeData->hasBillboardChangedAfterParsing(receivedPacket)
|
||||
&& !nodeData->hasSentBillboardBetweenKeyFrames()) {
|
||||
// this avatar changed their billboard and we haven't sent a packet in this keyframe
|
||||
broadcastBillboardPacket(avatarNode);
|
||||
nodeData->setHasSentBillboardBetweenKeyFrames(true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PacketTypeKillAvatar: {
|
||||
nodeList->processKillNode(receivedPacket);
|
||||
|
@ -185,6 +226,7 @@ void AvatarMixer::readPendingDatagrams() {
|
|||
}
|
||||
|
||||
const qint64 AVATAR_IDENTITY_KEYFRAME_MSECS = 5000;
|
||||
const qint64 AVATAR_BILLBOARD_KEYFRAME_MSECS = 5000;
|
||||
|
||||
void AvatarMixer::run() {
|
||||
commonInit(AVATAR_MIXER_LOGGING_NAME, NodeType::AvatarMixer);
|
||||
|
@ -202,6 +244,9 @@ void AvatarMixer::run() {
|
|||
QElapsedTimer identityTimer;
|
||||
identityTimer.start();
|
||||
|
||||
QElapsedTimer billboardTimer;
|
||||
billboardTimer.start();
|
||||
|
||||
while (!_isFinished) {
|
||||
|
||||
QCoreApplication::processEvents();
|
||||
|
@ -219,6 +264,11 @@ void AvatarMixer::run() {
|
|||
// restart the timer so we do it again in AVATAR_IDENTITY_KEYFRAME_MSECS
|
||||
identityTimer.restart();
|
||||
}
|
||||
|
||||
if (billboardTimer.elapsed() >= AVATAR_BILLBOARD_KEYFRAME_MSECS) {
|
||||
broadcastBillboardPackets();
|
||||
billboardTimer.restart();
|
||||
}
|
||||
|
||||
int usecToSleep = usecTimestamp(&startTime) + (++nextFrame * AVATAR_DATA_SEND_INTERVAL_USECS) - usecTimestampNow();
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
#include "AvatarMixerClientData.h"
|
||||
|
||||
AvatarMixerClientData::AvatarMixerClientData() :
|
||||
_hasSentIdentityBetweenKeyFrames(false)
|
||||
_hasSentIdentityBetweenKeyFrames(false),
|
||||
_hasSentBillboardBetweenKeyFrames(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -21,9 +21,15 @@ public:
|
|||
bool hasSentIdentityBetweenKeyFrames() const { return _hasSentIdentityBetweenKeyFrames; }
|
||||
void setHasSentIdentityBetweenKeyFrames(bool hasSentIdentityBetweenKeyFrames)
|
||||
{ _hasSentIdentityBetweenKeyFrames = hasSentIdentityBetweenKeyFrames; }
|
||||
|
||||
bool hasSentBillboardBetweenKeyFrames() const { return _hasSentBillboardBetweenKeyFrames; }
|
||||
void setHasSentBillboardBetweenKeyFrames(bool hasSentBillboardBetweenKeyFrames)
|
||||
{ _hasSentBillboardBetweenKeyFrames = hasSentBillboardBetweenKeyFrames; }
|
||||
|
||||
private:
|
||||
|
||||
bool _hasSentIdentityBetweenKeyFrames;
|
||||
bool _hasSentBillboardBetweenKeyFrames;
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__AvatarMixerClientData__) */
|
||||
|
|
137
examples/alternate-gameoflife.js
Normal file
|
@ -0,0 +1,137 @@
|
|||
// Add your JavaScript for assignment below this line
|
||||
|
||||
// The following is an example of Conway's Game of Life (http://en.wikipedia.org/wiki/Conway's_Game_of_Life)
|
||||
|
||||
var gameZ = 100;
|
||||
var NUMBER_OF_CELLS_EACH_DIMENSION = 64;
|
||||
var NUMBER_OF_CELLS = NUMBER_OF_CELLS_EACH_DIMENSION * NUMBER_OF_CELLS_EACH_DIMENSION;
|
||||
|
||||
var currentCells = [];
|
||||
var nextCells = [];
|
||||
|
||||
var METER_LENGTH = 1;
|
||||
var cellScale = (NUMBER_OF_CELLS_EACH_DIMENSION * METER_LENGTH) / NUMBER_OF_CELLS_EACH_DIMENSION;
|
||||
|
||||
// randomly populate the cell start values
|
||||
for (var i = 0; i < NUMBER_OF_CELLS_EACH_DIMENSION; i++) {
|
||||
// create the array to hold this row
|
||||
currentCells[i] = [];
|
||||
|
||||
// create the array to hold this row in the nextCells array
|
||||
nextCells[i] = [];
|
||||
|
||||
for (var j = 0; j < NUMBER_OF_CELLS_EACH_DIMENSION; j++) {
|
||||
currentCells[i][j] = Math.floor(Math.random() * 2);
|
||||
|
||||
// put the same value in the nextCells array for first board draw
|
||||
nextCells[i][j] = currentCells[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
function isNeighbourAlive(i, j) {
|
||||
if (i < 0 || i >= NUMBER_OF_CELLS_EACH_DIMENSION
|
||||
|| i < 0 || j >= NUMBER_OF_CELLS_EACH_DIMENSION) {
|
||||
return 0;
|
||||
} else {
|
||||
return currentCells[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
function updateCells() {
|
||||
var i = 0;
|
||||
var j = 0;
|
||||
|
||||
for (i = 0; i < NUMBER_OF_CELLS_EACH_DIMENSION; i++) {
|
||||
for (j = 0; j < NUMBER_OF_CELLS_EACH_DIMENSION; j++) {
|
||||
// figure out the number of live neighbours for the i-j cell
|
||||
var liveNeighbours =
|
||||
isNeighbourAlive(i + 1, j - 1) + isNeighbourAlive(i + 1, j) + isNeighbourAlive(i + 1, j + 1) +
|
||||
isNeighbourAlive(i, j - 1) + isNeighbourAlive(i, j + 1) +
|
||||
isNeighbourAlive(i - 1, j - 1) + isNeighbourAlive(i - 1, j) + isNeighbourAlive(i - 1, j + 1);
|
||||
|
||||
if (currentCells[i][j]) {
|
||||
// live cell
|
||||
|
||||
if (liveNeighbours < 2) {
|
||||
// rule #1 - under-population - this cell will die
|
||||
// mark it zero to mark the change
|
||||
nextCells[i][j] = 0;
|
||||
} else if (liveNeighbours < 4) {
|
||||
// rule #2 - this cell lives
|
||||
// mark it -1 to mark no change
|
||||
nextCells[i][j] = -1;
|
||||
} else {
|
||||
// rule #3 - overcrowding - this cell dies
|
||||
// mark it zero to mark the change
|
||||
nextCells[i][j] = 0;
|
||||
}
|
||||
} else {
|
||||
// dead cell
|
||||
if (liveNeighbours == 3) {
|
||||
// rule #4 - reproduction - this cell revives
|
||||
// mark it one to mark the change
|
||||
nextCells[i][j] = 1;
|
||||
} else {
|
||||
// this cell stays dead
|
||||
// mark it -1 for no change
|
||||
nextCells[i][j] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (Math.random() < 0.001) {
|
||||
// Random mutation to keep things interesting in there.
|
||||
nextCells[i][j] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < NUMBER_OF_CELLS_EACH_DIMENSION; i++) {
|
||||
for (j = 0; j < NUMBER_OF_CELLS_EACH_DIMENSION; j++) {
|
||||
if (nextCells[i][j] != -1) {
|
||||
// there has been a change to this cell, change the value in the currentCells array
|
||||
currentCells[i][j] = nextCells[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sendNextCells() {
|
||||
for (var i = 0; i < NUMBER_OF_CELLS_EACH_DIMENSION; i++) {
|
||||
for (var j = 0; j < NUMBER_OF_CELLS_EACH_DIMENSION; j++) {
|
||||
if (nextCells[i][j] != -1) {
|
||||
// there has been a change to the state of this cell, send it
|
||||
|
||||
// find the x and y position for this voxel, z = 0
|
||||
var x = j * cellScale;
|
||||
var y = i * cellScale;
|
||||
|
||||
// queue a packet to add a voxel for the new cell
|
||||
var color = (nextCells[i][j] == 1) ? 255 : 1;
|
||||
if (color == 255) {
|
||||
Voxels.setVoxel(x, y, gameZ, cellScale, color, color, color);
|
||||
} else {
|
||||
Voxels.setVoxel(x, y, gameZ, cellScale, 255, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var sentFirstBoard = false;
|
||||
|
||||
function step() {
|
||||
if (sentFirstBoard) {
|
||||
// we've already sent the first full board, perform a step in time
|
||||
updateCells();
|
||||
} else {
|
||||
// this will be our first board send
|
||||
sentFirstBoard = true;
|
||||
}
|
||||
|
||||
sendNextCells();
|
||||
}
|
||||
|
||||
print("here");
|
||||
//Script.willSendVisualDataCallback.connect(step);
|
||||
Voxels.setPacketsPerSecond(200);
|
||||
print("now here");
|
BIN
examples/cubes.svo
Normal file
|
@ -738,7 +738,7 @@ function endOrbitMode(event) {
|
|||
var cameraOrientation = Camera.getOrientation();
|
||||
var eulers = Quat.safeEulerAngles(cameraOrientation);
|
||||
MyAvatar.position = Camera.getPosition();
|
||||
MyAvatar.orientation = cameraOrientation;
|
||||
MyAvatar.headOrientation = cameraOrientation;
|
||||
Camera.stopLooking();
|
||||
Camera.setMode(oldMode);
|
||||
Camera.setOrientation(cameraOrientation);
|
||||
|
|
177
examples/hifi-interface-tools.svg
Normal file
|
@ -0,0 +1,177 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="124px" height="400px" viewBox="-0.5 0.5 124 400" enable-background="new -0.5 0.5 124 400" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<rect x="-0.5" y="120.382" width="62" height="40"/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#999999" d="M13.77,149.864c0.296,0.296,0.665,0.102,0.665,0.102s0.527-0.615,1.101-0.328
|
||||
c0.811,0.405,1.315-0.113,1.315-0.113l10.611-10.611l-1.419-1.419l-1.161-1.161l-10.61,10.61c0,0-0.575,0.449-0.169,1.261
|
||||
c0.287,0.573-0.384,1.045-0.384,1.045S13.474,149.569,13.77,149.864"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#CCCCCC" d="M25.913,135.042l2.173-2.173c0,0,1.898-1.905,3.256-0.547c0.68,0.68,1.083,1.627-0.546,3.257
|
||||
c-1.549,1.548-2.173,2.172-2.173,2.172L25.913,135.042z"/>
|
||||
</g>
|
||||
<g>
|
||||
|
||||
<rect x="22.984" y="135.651" transform="matrix(-0.7071 -0.7071 0.7071 -0.7071 -52.0828 253.0143)" fill="#CCCCCC" width="6.751" height="3.285"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M46.482,138.915h3.697v4.617c-1.004,0.344-2.107,0.516-3.311,0.516c-1.32,0-2.341-0.383-3.062-1.148
|
||||
s-1.081-1.857-1.081-3.275c0-1.383,0.395-2.459,1.184-3.229s1.895-1.154,3.316-1.154c0.539,0,1.048,0.051,1.526,0.152
|
||||
s0.896,0.23,1.251,0.387l-0.732,1.816c-0.617-0.305-1.295-0.457-2.033-0.457c-0.676,0-1.198,0.22-1.567,0.659
|
||||
s-0.554,1.067-0.554,1.884c0,0.801,0.167,1.411,0.501,1.831s0.815,0.63,1.444,0.63c0.344,0,0.66-0.033,0.949-0.1v-1.342h-1.529
|
||||
L46.482,138.915L46.482,138.915z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<rect x="-0.5" y="80.5" width="62" height="40"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M43.84,96.434h2.988c1.164,0,2.028,0.173,2.593,0.519s0.847,0.884,0.847,1.614
|
||||
c0,0.48-0.123,0.891-0.369,1.23s-0.57,0.559-0.973,0.656v0.059c0.531,0.141,0.916,0.375,1.154,0.703s0.357,0.754,0.357,1.277
|
||||
c0,0.777-0.292,1.39-0.876,1.837S48.182,105,47.174,105H43.84V96.434z M46.154,99.721h0.697c0.332,0,0.589-0.068,0.771-0.205
|
||||
s0.272-0.34,0.272-0.609c0-0.48-0.363-0.721-1.09-0.721h-0.65C46.154,98.186,46.154,99.721,46.154,99.721z M46.154,101.414v1.799
|
||||
h0.814c0.723,0,1.084-0.305,1.084-0.914c0-0.285-0.097-0.504-0.29-0.656s-0.474-0.229-0.841-0.229
|
||||
C46.921,101.414,46.154,101.414,46.154,101.414z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M18,106.06c-3,1-3,3-7,3c2,1,8,4,9,0C20.47,107.181,18,106.06,18,106.06z"/>
|
||||
<path fill="#CCCCCC" d="M19,105.06l2,2c0,0,3.952-4.712,7-9c3.048-4.287,7.32-10.785,3-7C28.399,93.338,22.048,100.772,19,105.06z
|
||||
"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<rect x="-0.5" y="40.5" width="62" height="40"/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<polygon fill="#A5A5A5" points="26,58.63 39,53.893 39,67.213 26,72.394 "/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#333333" d="M38,54.5v12.59l-12,5.032V58.757l12.204-4.468 M39,53.63l-13,4.873v14.162l13-5.33V53.63L39,53.63z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<polygon fill="#BFBFBF" points="13,67.213 13,53.893 25,58.63 25,72.394 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#BFBFBF" d="M12.887,54.289L25,58.757v13.365L13,67.09V54.5 M13,53.63v13.705l13,5.33V58.503L13,53.63L13,53.63z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<polygon fill="#FFFFFF" points="13.173,53.63 25.746,48.952 38.318,53.63 25.746,58.309 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#333333" d="M25.746,49.146l12.049,4.483l-12.049,4.483L13.697,53.63L25.746,49.146 M25.746,48.758L12.65,53.63
|
||||
l13.096,4.873l13.096-4.873L25.746,48.758L25.746,48.758z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M46.119,62.383V65.5h-2.314v-8.566h2.807c2.328,0,3.492,0.844,3.492,2.531c0,0.992-0.484,1.76-1.453,2.303
|
||||
l2.495,3.732h-2.625l-1.816-3.117H46.119z M46.119,60.643h0.434c0.809,0,1.213-0.357,1.213-1.072c0-0.59-0.396-0.885-1.189-0.885
|
||||
H46.12L46.119,60.643L46.119,60.643z"/>
|
||||
</g>
|
||||
<g>
|
||||
<polygon fill="#333333" points="7,59.5 9,59.5 10,59.5 15,59.5 16,59.5 18,59.5 18,64.5 16,64.5 15,64.5 10,64.5 9,64.5 7,64.5
|
||||
"/>
|
||||
<g>
|
||||
<g>
|
||||
<rect x="8" y="60.5" fill="#FFFFFF" width="9" height="3"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<rect x="-0.5" y="0.5" width="62" height="40"/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<polygon fill="#A5A5A5" points="26,18.63 39,13.893 39,27.213 26,32.394 "/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#333333" d="M38,14.5v12.59l-12,5.032V18.757l12.204-4.468 M39,13.63l-13,4.873v14.162l13-5.33V13.63L39,13.63z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<polygon fill="#BFBFBF" points="13,27.213 13,13.893 25,18.63 25,32.394 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#BFBFBF" d="M12.887,14.289L25,18.757v13.365L13,27.09V14.5 M13,13.63v13.705l13,5.33V18.503L13,13.63L13,13.63z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<polygon fill="#FFFFFF" points="13.173,13.63 25.746,8.952 38.318,13.63 25.746,18.309 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#333333" d="M25.746,9.146l12.049,4.483l-12.049,4.483L13.697,13.63L25.746,9.146 M25.746,8.758L12.65,13.63
|
||||
l13.096,4.873l13.096-4.873L25.746,8.758L25.746,8.758z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M48.41,16.934H51L48.193,25.5h-2.725l-2.795-8.566h2.602l1.166,4.342c0.242,0.965,0.375,1.637,0.398,2.016
|
||||
c0.027-0.273,0.082-0.615,0.164-1.025s0.154-0.732,0.217-0.967L48.41,16.934z"/>
|
||||
</g>
|
||||
<g>
|
||||
<polygon fill="#333333" points="7,19.5 10,19.5 10,16.5 15,16.5 15,19.5 18,19.5 18,24.5 15,24.5 15,27.5 10,27.5 10,24.5 7,24.5
|
||||
"/>
|
||||
<g>
|
||||
<g>
|
||||
<rect x="11" y="17.5" fill="#FFFFFF" width="3" height="9"/>
|
||||
</g>
|
||||
<g>
|
||||
<rect x="8" y="20.5" fill="#FFFFFF" width="9" height="3"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<rect x="-0.5" y="160.5" width="62" height="40"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M50.379,179.205c0,1.441-0.354,2.537-1.061,3.287s-1.742,1.125-3.105,1.125
|
||||
c-1.344,0-2.374-0.377-3.091-1.131s-1.075-1.852-1.075-3.293c0-1.426,0.356-2.515,1.069-3.267s1.749-1.128,3.108-1.128
|
||||
c1.363,0,2.396,0.373,3.1,1.119S50.379,177.76,50.379,179.205z M44.484,179.205c0,1.656,0.576,2.484,1.729,2.484
|
||||
c0.586,0,1.021-0.201,1.304-0.604s0.425-1.029,0.425-1.881c0-0.855-0.144-1.487-0.431-1.896s-0.716-0.612-1.286-0.612
|
||||
C45.064,176.697,44.484,177.533,44.484,179.205z"/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<polyline fill="none" stroke="#CCCCCC" stroke-miterlimit="10" points="19.944,187.389 19.944,188.389 19.031,187.981 "/>
|
||||
|
||||
<line fill="none" stroke="#CCCCCC" stroke-miterlimit="10" stroke-dasharray="1.9973,1.9973" x1="17.208" y1="187.166" x2="10.825" y2="184.315"/>
|
||||
<polyline fill="none" stroke="#CCCCCC" stroke-miterlimit="10" points="9.913,183.908 9,183.5 9,182.5 "/>
|
||||
<line fill="none" stroke="#CCCCCC" stroke-miterlimit="10" stroke-dasharray="2,2" x1="8.5" y1="180.5" x2="8.5" y2="173.5"/>
|
||||
<polyline fill="none" stroke="#CCCCCC" stroke-miterlimit="10" points="9,172.5 9,171.5 9.927,171.876 "/>
|
||||
|
||||
<line fill="none" stroke="#CCCCCC" stroke-miterlimit="10" stroke-dasharray="1.9625,1.9625" x1="11.745" y1="172.615" x2="18.109" y2="175.199"/>
|
||||
<polyline fill="none" stroke="#CCCCCC" stroke-miterlimit="10" points="19.018,175.568 19.944,175.944 19.944,176.944 "/>
|
||||
<line fill="none" stroke="#CCCCCC" stroke-miterlimit="10" stroke-dasharray="2,2" x1="19.5" y1="179.5" x2="19.5" y2="186.5"/>
|
||||
</g>
|
||||
</g>
|
||||
<polyline fill="none" stroke="#CCCCCC" stroke-miterlimit="10" stroke-dasharray="2,2" points="19.944,175.944 30,171.5 20,168.5
|
||||
9,171.5 "/>
|
||||
<polyline fill="none" stroke="#CCCCCC" stroke-miterlimit="10" stroke-dasharray="2,2" points="20.333,188.611 29.5,183.5
|
||||
29.5,171.5 "/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 7.5 KiB |
BIN
examples/invader.svo
Normal file
BIN
examples/invader2.svo
Normal file
|
@ -156,6 +156,13 @@ var line3d = Overlays.addOverlay("line3d", {
|
|||
lineWidth: 5
|
||||
});
|
||||
|
||||
// this will display the content of your clipboard at the origin of the domain
|
||||
var clipboardPreview = Overlays.addOverlay("clipboard", {
|
||||
position: { x: 0, y: 0, z: 0},
|
||||
size: 1 / 32,
|
||||
visible: true
|
||||
});
|
||||
|
||||
|
||||
// When our script shuts down, we should clean up all of our overlays
|
||||
function scriptEnding() {
|
||||
|
@ -170,6 +177,7 @@ function scriptEnding() {
|
|||
Overlays.deleteOverlay(solidCube);
|
||||
Overlays.deleteOverlay(sphere);
|
||||
Overlays.deleteOverlay(line3d);
|
||||
Overlays.deleteOverlay(clipboardPreview);
|
||||
}
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
||||
|
|
BIN
examples/slider.jpg
Normal file
After Width: | Height: | Size: 8.6 KiB |
BIN
examples/slider.png
Normal file
After Width: | Height: | Size: 10 KiB |
20
examples/swatches.svg
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 270 109" enable-background="new 0 0 270 109" xml:space="preserve">
|
||||
|
||||
<rect fill="#FFFFFF" x="0" y="0" width="270" height="109"/>
|
||||
<g>
|
||||
<path fill="#1E1E1E" d="M0,0v54h270V0H0z M39,39H15V15h24V39z M66,39H42V15h24V39z M93,39H69V15h24V39z M120,39H96V15h24V39z
|
||||
M147,39h-24V15h24V39z M174,39h-24V15h24V39z M201,39h-24V15h24V39z M228,39h-24V15h24V39z M255,39h-24V15h24V39z"/>
|
||||
</g>
|
||||
|
||||
<g>
|
||||
<path fill="#1E1E1E" d="M0,55v54h270V55H0z M39,94H15V70h6.2l5.8,5.8l5.8-5.8H39V94z M66,94H42V70h6.2l5.8,5.8l5.8-5.8H66V94z
|
||||
M93,94H69V70h6.2l5.8,5.8l5.8-5.8H93V94z M120,94H96V70h6.2l5.8,5.8l5.8-5.8h6.2V94z M147,94h-24V70h6.2l5.8,5.8l5.8-5.8h6.2V94z
|
||||
M174,94h-24V70h6.2l5.8,5.8l5.8-5.8h6.2V94z M201,94h-24V70h6.2l5.8,5.8l5.8-5.8h6.2V94z M228,94h-24V70h6.2l5.8,5.8l5.8-5.8h6.2
|
||||
V94z M255,94h-24V70h6.2l5.8,5.8l5.8-5.8h6.2V94z"/>
|
||||
</g>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
177
examples/testing-hifi-interface-tools.svg
Normal file
|
@ -0,0 +1,177 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="124px" height="400px" viewBox="-0.5 0.5 124 400" enable-background="new -0.5 0.5 124 400" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<rect x="-0.5" y="120.382" width="62" height="40"/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#999999" d="M13.77,149.864c0.296,0.296,0.665,0.102,0.665,0.102s0.527-0.615,1.101-0.328
|
||||
c0.811,0.405,1.315-0.113,1.315-0.113l10.611-10.611l-1.419-1.419l-1.161-1.161l-10.61,10.61c0,0-0.575,0.449-0.169,1.261
|
||||
c0.287,0.573-0.384,1.045-0.384,1.045S13.474,149.569,13.77,149.864"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#CCCCCC" d="M25.913,135.042l2.173-2.173c0,0,1.898-1.905,3.256-0.547c0.68,0.68,1.083,1.627-0.546,3.257
|
||||
c-1.549,1.548-2.173,2.172-2.173,2.172L25.913,135.042z"/>
|
||||
</g>
|
||||
<g>
|
||||
|
||||
<rect x="22.984" y="135.651" transform="matrix(-0.7071 -0.7071 0.7071 -0.7071 -52.0828 253.0143)" fill="#CCCCCC" width="6.751" height="3.285"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M46.482,138.915h3.697v4.617c-1.004,0.344-2.107,0.516-3.311,0.516c-1.32,0-2.341-0.383-3.062-1.148
|
||||
s-1.081-1.857-1.081-3.275c0-1.383,0.395-2.459,1.184-3.229s1.895-1.154,3.316-1.154c0.539,0,1.048,0.051,1.526,0.152
|
||||
s0.896,0.23,1.251,0.387l-0.732,1.816c-0.617-0.305-1.295-0.457-2.033-0.457c-0.676,0-1.198,0.22-1.567,0.659
|
||||
s-0.554,1.067-0.554,1.884c0,0.801,0.167,1.411,0.501,1.831s0.815,0.63,1.444,0.63c0.344,0,0.66-0.033,0.949-0.1v-1.342h-1.529
|
||||
L46.482,138.915L46.482,138.915z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<rect x="-0.5" y="80.5" width="62" height="40"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M43.84,96.434h2.988c1.164,0,2.028,0.173,2.593,0.519s0.847,0.884,0.847,1.614
|
||||
c0,0.48-0.123,0.891-0.369,1.23s-0.57,0.559-0.973,0.656v0.059c0.531,0.141,0.916,0.375,1.154,0.703s0.357,0.754,0.357,1.277
|
||||
c0,0.777-0.292,1.39-0.876,1.837S48.182,105,47.174,105H43.84V96.434z M46.154,99.721h0.697c0.332,0,0.589-0.068,0.771-0.205
|
||||
s0.272-0.34,0.272-0.609c0-0.48-0.363-0.721-1.09-0.721h-0.65C46.154,98.186,46.154,99.721,46.154,99.721z M46.154,101.414v1.799
|
||||
h0.814c0.723,0,1.084-0.305,1.084-0.914c0-0.285-0.097-0.504-0.29-0.656s-0.474-0.229-0.841-0.229
|
||||
C46.921,101.414,46.154,101.414,46.154,101.414z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M18,106.06c-3,1-3,3-7,3c2,1,8,4,9,0C20.47,107.181,18,106.06,18,106.06z"/>
|
||||
<path fill="#CCCCCC" d="M19,105.06l2,2c0,0,3.952-4.712,7-9c3.048-4.287,7.32-10.785,3-7C28.399,93.338,22.048,100.772,19,105.06z
|
||||
"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<rect x="-0.5" y="40.5" width="62" height="40" fill="#888888"/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<polygon fill="#A5A5A5" points="26,58.63 39,53.893 39,67.213 26,72.394 "/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#333333" d="M38,54.5v12.59l-12,5.032V58.757l12.204-4.468 M39,53.63l-13,4.873v14.162l13-5.33V53.63L39,53.63z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<polygon fill="#BFBFBF" points="13,67.213 13,53.893 25,58.63 25,72.394 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#BFBFBF" d="M12.887,54.289L25,58.757v13.365L13,67.09V54.5 M13,53.63v13.705l13,5.33V58.503L13,53.63L13,53.63z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<polygon fill="#FFFFFF" points="13.173,53.63 25.746,48.952 38.318,53.63 25.746,58.309 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#333333" d="M25.746,49.146l12.049,4.483l-12.049,4.483L13.697,53.63L25.746,49.146 M25.746,48.758L12.65,53.63
|
||||
l13.096,4.873l13.096-4.873L25.746,48.758L25.746,48.758z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M46.119,62.383V65.5h-2.314v-8.566h2.807c2.328,0,3.492,0.844,3.492,2.531c0,0.992-0.484,1.76-1.453,2.303
|
||||
l2.495,3.732h-2.625l-1.816-3.117H46.119z M46.119,60.643h0.434c0.809,0,1.213-0.357,1.213-1.072c0-0.59-0.396-0.885-1.189-0.885
|
||||
H46.12L46.119,60.643L46.119,60.643z"/>
|
||||
</g>
|
||||
<g>
|
||||
<polygon fill="#333333" points="7,59.5 9,59.5 10,59.5 15,59.5 16,59.5 18,59.5 18,64.5 16,64.5 15,64.5 10,64.5 9,64.5 7,64.5
|
||||
"/>
|
||||
<g>
|
||||
<g>
|
||||
<rect x="8" y="60.5" fill="#FFFFFF" width="9" height="3"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<rect x="-0.5" y="0.5" width="62" height="40"/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<polygon fill="#A5A5A5" points="26,18.63 39,13.893 39,27.213 26,32.394 "/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#333333" d="M38,14.5v12.59l-12,5.032V18.757l12.204-4.468 M39,13.63l-13,4.873v14.162l13-5.33V13.63L39,13.63z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<polygon fill="#BFBFBF" points="13,27.213 13,13.893 25,18.63 25,32.394 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#BFBFBF" d="M12.887,14.289L25,18.757v13.365L13,27.09V14.5 M13,13.63v13.705l13,5.33V18.503L13,13.63L13,13.63z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<polygon fill="#FFFFFF" points="13.173,13.63 25.746,8.952 38.318,13.63 25.746,18.309 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#333333" d="M25.746,9.146l12.049,4.483l-12.049,4.483L13.697,13.63L25.746,9.146 M25.746,8.758L12.65,13.63
|
||||
l13.096,4.873l13.096-4.873L25.746,8.758L25.746,8.758z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M48.41,16.934H51L48.193,25.5h-2.725l-2.795-8.566h2.602l1.166,4.342c0.242,0.965,0.375,1.637,0.398,2.016
|
||||
c0.027-0.273,0.082-0.615,0.164-1.025s0.154-0.732,0.217-0.967L48.41,16.934z"/>
|
||||
</g>
|
||||
<g>
|
||||
<polygon fill="#333333" points="7,19.5 10,19.5 10,16.5 15,16.5 15,19.5 18,19.5 18,24.5 15,24.5 15,27.5 10,27.5 10,24.5 7,24.5
|
||||
"/>
|
||||
<g>
|
||||
<g>
|
||||
<rect x="11" y="17.5" fill="#FFFFFF" width="3" height="9"/>
|
||||
</g>
|
||||
<g>
|
||||
<rect x="8" y="20.5" fill="#FFFFFF" width="9" height="3"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<rect x="-0.5" y="160.5" width="62" height="40"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M50.379,179.205c0,1.441-0.354,2.537-1.061,3.287s-1.742,1.125-3.105,1.125
|
||||
c-1.344,0-2.374-0.377-3.091-1.131s-1.075-1.852-1.075-3.293c0-1.426,0.356-2.515,1.069-3.267s1.749-1.128,3.108-1.128
|
||||
c1.363,0,2.396,0.373,3.1,1.119S50.379,177.76,50.379,179.205z M44.484,179.205c0,1.656,0.576,2.484,1.729,2.484
|
||||
c0.586,0,1.021-0.201,1.304-0.604s0.425-1.029,0.425-1.881c0-0.855-0.144-1.487-0.431-1.896s-0.716-0.612-1.286-0.612
|
||||
C45.064,176.697,44.484,177.533,44.484,179.205z"/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<polyline fill="none" stroke="#CCCCCC" stroke-miterlimit="10" points="19.944,187.389 19.944,188.389 19.031,187.981 "/>
|
||||
|
||||
<line fill="none" stroke="#CCCCCC" stroke-miterlimit="10" stroke-dasharray="1.9973,1.9973" x1="17.208" y1="187.166" x2="10.825" y2="184.315"/>
|
||||
<polyline fill="none" stroke="#CCCCCC" stroke-miterlimit="10" points="9.913,183.908 9,183.5 9,182.5 "/>
|
||||
<line fill="none" stroke="#CCCCCC" stroke-miterlimit="10" stroke-dasharray="2,2" x1="8.5" y1="180.5" x2="8.5" y2="173.5"/>
|
||||
<polyline fill="none" stroke="#CCCCCC" stroke-miterlimit="10" points="9,172.5 9,171.5 9.927,171.876 "/>
|
||||
|
||||
<line fill="none" stroke="#CCCCCC" stroke-miterlimit="10" stroke-dasharray="1.9625,1.9625" x1="11.745" y1="172.615" x2="18.109" y2="175.199"/>
|
||||
<polyline fill="none" stroke="#CCCCCC" stroke-miterlimit="10" points="19.018,175.568 19.944,175.944 19.944,176.944 "/>
|
||||
<line fill="none" stroke="#CCCCCC" stroke-miterlimit="10" stroke-dasharray="2,2" x1="19.5" y1="179.5" x2="19.5" y2="186.5"/>
|
||||
</g>
|
||||
</g>
|
||||
<polyline fill="none" stroke="#CCCCCC" stroke-miterlimit="10" stroke-dasharray="2,2" points="19.944,175.944 30,171.5 20,168.5
|
||||
9,171.5 "/>
|
||||
<polyline fill="none" stroke="#CCCCCC" stroke-miterlimit="10" stroke-dasharray="2,2" points="20.333,188.611 29.5,183.5
|
||||
29.5,171.5 "/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 7.5 KiB |
20
examples/testing-swatches
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 270 109" enable-background="new 0 0 270 109" xml:space="preserve">
|
||||
|
||||
<rect fill="#FFFFFF" x="0" y="0" width="270" height="109"/>
|
||||
<g>
|
||||
<path fill="#1E1E1E" d="M0,0v54h270V0H0z M39,39H15V15h24V39z M66,39H42V15h24V39z M93,39H69V15h24V39z M120,39H96V15h24V39z
|
||||
M147,39h-24V15h24V39z M174,39h-24V15h24V39z M201,39h-24V15h24V39z M228,39h-24V15h24V39z M255,39h-24V15h24V39z"/>
|
||||
</g>
|
||||
|
||||
<g>
|
||||
<path fill="#1E1E1E" d="M0,55v54h270V55H0z M39,94H15V70h6.2l5.8,5.8l5.8-5.8H39V94z M66,94H42V70h6.2l5.8,5.8l5.8-5.8H66V94z
|
||||
M93,94H69V70h6.2l5.8,5.8l5.8-5.8H93V94z M120,94H96V70h6.2l5.8,5.8l5.8-5.8h6.2V94z M147,94h-24V70h6.2l5.8,5.8l5.8-5.8h6.2V94z
|
||||
M174,94h-24V70h6.2l5.8,5.8l5.8-5.8h6.2V94z M201,94h-24V70h6.2l5.8,5.8l5.8-5.8h6.2V94z M228,94h-24V70h6.2l5.8,5.8l5.8-5.8h6.2
|
||||
V94z M255,94h-24V70h6.2l5.8,5.8l5.8-5.8h6.2V94z"/>
|
||||
</g>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
20
examples/testing-swatches.svg
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 270 109" enable-background="new 0 0 270 109" xml:space="preserve">
|
||||
|
||||
<rect fill="#FFFFFF" x="0" y="0" width="270" height="109"/>
|
||||
<g>
|
||||
<path fill="#1E1E1E" d="M0,0v54h270V0H0z M39,39H15V15h24V39z M66,39H42V15h24V39z M93,39H69V15h24V39z M120,39H96V15h24V39z
|
||||
M147,39h-24V15h24V39z M174,39h-24V15h24V39z M201,39h-24V15h24V39z M228,39h-24V15h24V39z M255,39h-24V15h24V39z"/>
|
||||
</g>
|
||||
|
||||
<g>
|
||||
<path fill="#1E1E1E" d="M0,55v54h270V55H0z M39,94H15V70h6.2l5.8,5.8l5.8-5.8H39V94z M66,94H42V70h6.2l5.8,5.8l5.8-5.8H66V94z
|
||||
M93,94H69V70h6.2l5.8,5.8l5.8-5.8H93V94z M120,94H96V70h6.2l5.8,5.8l5.8-5.8h6.2V94z M147,94h-24V70h6.2l5.8,5.8l5.8-5.8h6.2V94z
|
||||
M174,94h-24V70h6.2l5.8,5.8l5.8-5.8h6.2V94z M201,94h-24V70h6.2l5.8,5.8l5.8-5.8h6.2V94z M228,94h-24V70h6.2l5.8,5.8l5.8-5.8h6.2
|
||||
V94z M255,94h-24V70h6.2l5.8,5.8l5.8-5.8h6.2V94z"/>
|
||||
</g>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
BIN
examples/thumb.jpg
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
examples/thumb.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
36
examples/touchVsMouse.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// toucheVsMouse.js
|
||||
// hifi
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 1/28/14.
|
||||
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
||||
//
|
||||
// This is an example script that demonstrates use of the Controller class
|
||||
//
|
||||
//
|
||||
|
||||
function touchBeginEvent(event) {
|
||||
print("touchBeginEvent event.x,y=" + event.x + ", " + event.y);
|
||||
}
|
||||
|
||||
function touchEndEvent(event) {
|
||||
print("touchEndEvent event.x,y=" + event.x + ", " + event.y);
|
||||
}
|
||||
|
||||
function touchUpdateEvent(event) {
|
||||
print("touchUpdateEvent event.x,y=" + event.x + ", " + event.y);
|
||||
}
|
||||
function mouseMoveEvent(event) {
|
||||
print("mouseMoveEvent event.x,y=" + event.x + ", " + event.y);
|
||||
}
|
||||
|
||||
// Map the mouse events to our functions
|
||||
Controller.touchBeginEvent.connect(touchBeginEvent);
|
||||
Controller.touchUpdateEvent.connect(touchUpdateEvent);
|
||||
Controller.touchEndEvent.connect(touchEndEvent);
|
||||
|
||||
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||
|
||||
function scriptEnding() {
|
||||
}
|
||||
Script.scriptEnding.connect(scriptEnding);
|
|
@ -98,6 +98,7 @@ const int MIRROR_VIEW_HEIGHT = 215;
|
|||
const float MIRROR_FULLSCREEN_DISTANCE = 0.35f;
|
||||
const float MIRROR_REARVIEW_DISTANCE = 0.65f;
|
||||
const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f;
|
||||
const float MIRROR_FIELD_OF_VIEW = 30.0f;
|
||||
|
||||
const QString CHECK_VERSION_URL = "http://highfidelity.io/latestVersion.xml";
|
||||
const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/hifi.skipversion";
|
||||
|
@ -255,6 +256,11 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
|||
connect(identityPacketTimer, &QTimer::timeout, _myAvatar, &MyAvatar::sendIdentityPacket);
|
||||
identityPacketTimer->start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS);
|
||||
|
||||
// send the billboard packet for our avatar every few seconds
|
||||
QTimer* billboardPacketTimer = new QTimer();
|
||||
connect(billboardPacketTimer, &QTimer::timeout, _myAvatar, &MyAvatar::sendBillboardPacket);
|
||||
billboardPacketTimer->start(AVATAR_BILLBOARD_PACKET_SEND_INTERVAL_MSECS);
|
||||
|
||||
QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
|
||||
|
||||
_networkAccessManager = new QNetworkAccessManager(this);
|
||||
|
@ -527,73 +533,8 @@ void Application::paintGL() {
|
|||
_glowEffect.render();
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
|
||||
|
||||
bool eyeRelativeCamera = false;
|
||||
if (_rearMirrorTools->getZoomLevel() == BODY) {
|
||||
_mirrorCamera.setDistance(MIRROR_REARVIEW_BODY_DISTANCE * _myAvatar->getScale());
|
||||
_mirrorCamera.setTargetPosition(_myAvatar->getChestPosition());
|
||||
} else { // HEAD zoom level
|
||||
_mirrorCamera.setDistance(MIRROR_REARVIEW_DISTANCE * _myAvatar->getScale());
|
||||
if (_myAvatar->getSkeletonModel().isActive() && _myAvatar->getHead()->getFaceModel().isActive()) {
|
||||
// as a hack until we have a better way of dealing with coordinate precision issues, reposition the
|
||||
// face/body so that the average eye position lies at the origin
|
||||
eyeRelativeCamera = true;
|
||||
_mirrorCamera.setTargetPosition(glm::vec3());
|
||||
|
||||
} else {
|
||||
_mirrorCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition());
|
||||
}
|
||||
}
|
||||
|
||||
_mirrorCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PIf, 0.0f)));
|
||||
_mirrorCamera.update(1.0f/_fps);
|
||||
|
||||
// set the bounds of rear mirror view
|
||||
glViewport(_mirrorViewRect.x(), _glWidget->height() - _mirrorViewRect.y() - _mirrorViewRect.height(),
|
||||
_mirrorViewRect.width(), _mirrorViewRect.height());
|
||||
glScissor(_mirrorViewRect.x(), _glWidget->height() - _mirrorViewRect.y() - _mirrorViewRect.height(),
|
||||
_mirrorViewRect.width(), _mirrorViewRect.height());
|
||||
bool updateViewFrustum = false;
|
||||
updateProjectionMatrix(_mirrorCamera, updateViewFrustum);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
// render rear mirror view
|
||||
glPushMatrix();
|
||||
if (eyeRelativeCamera) {
|
||||
// save absolute translations
|
||||
glm::vec3 absoluteSkeletonTranslation = _myAvatar->getSkeletonModel().getTranslation();
|
||||
glm::vec3 absoluteFaceTranslation = _myAvatar->getHead()->getFaceModel().getTranslation();
|
||||
|
||||
// get the eye positions relative to the neck and use them to set the face translation
|
||||
glm::vec3 leftEyePosition, rightEyePosition;
|
||||
_myAvatar->getHead()->getFaceModel().setTranslation(glm::vec3());
|
||||
_myAvatar->getHead()->getFaceModel().getEyePositions(leftEyePosition, rightEyePosition);
|
||||
_myAvatar->getHead()->getFaceModel().setTranslation((leftEyePosition + rightEyePosition) * -0.5f);
|
||||
|
||||
// get the neck position relative to the body and use it to set the skeleton translation
|
||||
glm::vec3 neckPosition;
|
||||
_myAvatar->getSkeletonModel().setTranslation(glm::vec3());
|
||||
_myAvatar->getSkeletonModel().getNeckPosition(neckPosition);
|
||||
_myAvatar->getSkeletonModel().setTranslation(_myAvatar->getHead()->getFaceModel().getTranslation() -
|
||||
neckPosition);
|
||||
|
||||
displaySide(_mirrorCamera, true);
|
||||
|
||||
// restore absolute translations
|
||||
_myAvatar->getSkeletonModel().setTranslation(absoluteSkeletonTranslation);
|
||||
_myAvatar->getHead()->getFaceModel().setTranslation(absoluteFaceTranslation);
|
||||
} else {
|
||||
displaySide(_mirrorCamera, true);
|
||||
}
|
||||
glPopMatrix();
|
||||
|
||||
_rearMirrorTools->render(false);
|
||||
|
||||
// reset Viewport and projection matrix
|
||||
glViewport(0, 0, _glWidget->width(), _glWidget->height());
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
updateProjectionMatrix(_myCamera, updateViewFrustum);
|
||||
renderRearViewMirror(_mirrorViewRect);
|
||||
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {
|
||||
_rearMirrorTools->render(true);
|
||||
}
|
||||
|
@ -2743,6 +2684,24 @@ void Application::setupWorldLight() {
|
|||
glMateriali(GL_FRONT, GL_SHININESS, 96);
|
||||
}
|
||||
|
||||
QImage Application::renderAvatarBillboard() {
|
||||
_textureCache.getPrimaryFramebufferObject()->bind();
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
const int BILLBOARD_SIZE = 64;
|
||||
renderRearViewMirror(QRect(0, _glWidget->height() - BILLBOARD_SIZE, BILLBOARD_SIZE, BILLBOARD_SIZE), true);
|
||||
|
||||
QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32);
|
||||
glReadPixels(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE, GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
_textureCache.getPrimaryFramebufferObject()->release();
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide()");
|
||||
// transform by eye offset
|
||||
|
@ -3660,6 +3619,84 @@ void Application::renderCoverageMapsRecursively(CoverageMap* map) {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::renderRearViewMirror(const QRect& region, bool billboard) {
|
||||
bool eyeRelativeCamera = false;
|
||||
if (billboard) {
|
||||
_mirrorCamera.setFieldOfView(BILLBOARD_FIELD_OF_VIEW);
|
||||
_mirrorCamera.setDistance(BILLBOARD_DISTANCE * _myAvatar->getScale());
|
||||
_mirrorCamera.setTargetPosition(_myAvatar->getPosition());
|
||||
|
||||
} else if (_rearMirrorTools->getZoomLevel() == BODY) {
|
||||
_mirrorCamera.setFieldOfView(MIRROR_FIELD_OF_VIEW);
|
||||
_mirrorCamera.setDistance(MIRROR_REARVIEW_BODY_DISTANCE * _myAvatar->getScale());
|
||||
_mirrorCamera.setTargetPosition(_myAvatar->getChestPosition());
|
||||
|
||||
} else { // HEAD zoom level
|
||||
_mirrorCamera.setFieldOfView(MIRROR_FIELD_OF_VIEW);
|
||||
_mirrorCamera.setDistance(MIRROR_REARVIEW_DISTANCE * _myAvatar->getScale());
|
||||
if (_myAvatar->getSkeletonModel().isActive() && _myAvatar->getHead()->getFaceModel().isActive()) {
|
||||
// as a hack until we have a better way of dealing with coordinate precision issues, reposition the
|
||||
// face/body so that the average eye position lies at the origin
|
||||
eyeRelativeCamera = true;
|
||||
_mirrorCamera.setTargetPosition(glm::vec3());
|
||||
|
||||
} else {
|
||||
_mirrorCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition());
|
||||
}
|
||||
}
|
||||
_mirrorCamera.setAspectRatio((float)region.width() / region.height());
|
||||
|
||||
_mirrorCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PIf, 0.0f)));
|
||||
_mirrorCamera.update(1.0f/_fps);
|
||||
|
||||
// set the bounds of rear mirror view
|
||||
glViewport(region.x(), _glWidget->height() - region.y() - region.height(), region.width(), region.height());
|
||||
glScissor(region.x(), _glWidget->height() - region.y() - region.height(), region.width(), region.height());
|
||||
bool updateViewFrustum = false;
|
||||
updateProjectionMatrix(_mirrorCamera, updateViewFrustum);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
// render rear mirror view
|
||||
glPushMatrix();
|
||||
if (eyeRelativeCamera) {
|
||||
// save absolute translations
|
||||
glm::vec3 absoluteSkeletonTranslation = _myAvatar->getSkeletonModel().getTranslation();
|
||||
glm::vec3 absoluteFaceTranslation = _myAvatar->getHead()->getFaceModel().getTranslation();
|
||||
|
||||
// get the eye positions relative to the neck and use them to set the face translation
|
||||
glm::vec3 leftEyePosition, rightEyePosition;
|
||||
_myAvatar->getHead()->getFaceModel().setTranslation(glm::vec3());
|
||||
_myAvatar->getHead()->getFaceModel().getEyePositions(leftEyePosition, rightEyePosition);
|
||||
_myAvatar->getHead()->getFaceModel().setTranslation((leftEyePosition + rightEyePosition) * -0.5f);
|
||||
|
||||
// get the neck position relative to the body and use it to set the skeleton translation
|
||||
glm::vec3 neckPosition;
|
||||
_myAvatar->getSkeletonModel().setTranslation(glm::vec3());
|
||||
_myAvatar->getSkeletonModel().getNeckPosition(neckPosition);
|
||||
_myAvatar->getSkeletonModel().setTranslation(_myAvatar->getHead()->getFaceModel().getTranslation() -
|
||||
neckPosition);
|
||||
|
||||
displaySide(_mirrorCamera, true);
|
||||
|
||||
// restore absolute translations
|
||||
_myAvatar->getSkeletonModel().setTranslation(absoluteSkeletonTranslation);
|
||||
_myAvatar->getHead()->getFaceModel().setTranslation(absoluteFaceTranslation);
|
||||
} else {
|
||||
displaySide(_mirrorCamera, true);
|
||||
}
|
||||
glPopMatrix();
|
||||
|
||||
if (!billboard) {
|
||||
_rearMirrorTools->render(false);
|
||||
}
|
||||
|
||||
// reset Viewport and projection matrix
|
||||
glViewport(0, 0, _glWidget->width(), _glWidget->height());
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
updateProjectionMatrix(_myCamera, updateViewFrustum);
|
||||
}
|
||||
|
||||
// renderViewFrustum()
|
||||
//
|
||||
// Description: this will render the view frustum bounds for EITHER the head
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include <QApplication>
|
||||
#include <QAction>
|
||||
#include <QImage>
|
||||
#include <QSettings>
|
||||
#include <QTouchEvent>
|
||||
#include <QList>
|
||||
|
@ -96,6 +97,9 @@ static const float NODE_KILLED_BLUE = 0.0f;
|
|||
|
||||
static const QString SNAPSHOT_EXTENSION = ".jpg";
|
||||
|
||||
static const float BILLBOARD_FIELD_OF_VIEW = 30.0f;
|
||||
static const float BILLBOARD_DISTANCE = 5.0f;
|
||||
|
||||
class Application : public QApplication {
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -185,6 +189,8 @@ public:
|
|||
|
||||
void setupWorldLight();
|
||||
|
||||
QImage renderAvatarBillboard();
|
||||
|
||||
void displaySide(Camera& whichCamera, bool selfAvatarOnly = false);
|
||||
|
||||
/// Loads a view matrix that incorporates the specified model translation without the precision issues that can
|
||||
|
@ -200,6 +206,8 @@ public:
|
|||
void computeOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal,
|
||||
float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const;
|
||||
|
||||
|
||||
|
||||
VoxelShader& getVoxelShader() { return _voxelShader; }
|
||||
PointShader& getPointShader() { return _pointShader; }
|
||||
FileLogger* getLogger() { return _logger; }
|
||||
|
@ -328,7 +336,7 @@ private:
|
|||
void displayStats();
|
||||
void checkStatsClick();
|
||||
void toggleStatsExpanded();
|
||||
void renderAvatars(bool forceRenderHead, bool selfAvatarOnly = false);
|
||||
void renderRearViewMirror(const QRect& region, bool billboard = false);
|
||||
void renderViewFrustum(ViewFrustum& viewFrustum);
|
||||
|
||||
void checkBandwidthMeterClick();
|
||||
|
|
|
@ -98,7 +98,8 @@ void DatagramProcessor::processDatagrams() {
|
|||
break;
|
||||
case PacketTypeBulkAvatarData:
|
||||
case PacketTypeKillAvatar:
|
||||
case PacketTypeAvatarIdentity: {
|
||||
case PacketTypeAvatarIdentity:
|
||||
case PacketTypeAvatarBillboard: {
|
||||
// update having heard from the avatar-mixer and record the bytes received
|
||||
SharedNodePointer avatarMixer = nodeList->sendingNodeForPacket(incomingPacket);
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "Physics.h"
|
||||
#include "world.h"
|
||||
#include "devices/OculusManager.h"
|
||||
#include "renderer/TextureCache.h"
|
||||
#include "ui/TextRenderer.h"
|
||||
|
||||
using namespace std;
|
||||
|
@ -107,6 +108,10 @@ glm::quat Avatar::getWorldAlignedOrientation () const {
|
|||
return computeRotationFromBodyToWorldUp() * getOrientation();
|
||||
}
|
||||
|
||||
float Avatar::getLODDistance() const {
|
||||
return glm::distance(Application::getInstance()->getCamera()->getPosition(), _position) / _scale;
|
||||
}
|
||||
|
||||
void Avatar::simulate(float deltaTime) {
|
||||
if (_scale != _targetScale) {
|
||||
setScale(_targetScale);
|
||||
|
@ -116,9 +121,9 @@ void Avatar::simulate(float deltaTime) {
|
|||
glm::vec3 oldVelocity = getVelocity();
|
||||
|
||||
getHand()->simulate(deltaTime, false);
|
||||
_skeletonModel.setLODDistance(getLODDistance());
|
||||
_skeletonModel.simulate(deltaTime);
|
||||
Head* head = getHead();
|
||||
head->setBodyRotation(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll));
|
||||
glm::vec3 headPosition;
|
||||
if (!_skeletonModel.getHeadPosition(headPosition)) {
|
||||
headPosition = _position;
|
||||
|
@ -282,9 +287,11 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
|
|||
}
|
||||
|
||||
void Avatar::renderBody(bool forceRenderHead) {
|
||||
// Render the body's voxels and head
|
||||
glm::vec3 pos = getPosition();
|
||||
//printf("Render other at %.3f, %.2f, %.2f\n", pos.x, pos.y, pos.z);
|
||||
const float BILLBOARD_DISTANCE = 40.0f;
|
||||
if (!_billboard.isEmpty() && getLODDistance() >= BILLBOARD_DISTANCE) {
|
||||
renderBillboard();
|
||||
return;
|
||||
}
|
||||
_skeletonModel.render(1.0f);
|
||||
if (forceRenderHead) {
|
||||
getHead()->render(1.0f);
|
||||
|
@ -292,6 +299,62 @@ void Avatar::renderBody(bool forceRenderHead) {
|
|||
getHand()->render(false);
|
||||
}
|
||||
|
||||
void Avatar::renderBillboard() {
|
||||
if (!_billboardTexture) {
|
||||
QImage image = QImage::fromData(_billboard).convertToFormat(QImage::Format_ARGB32);
|
||||
|
||||
_billboardTexture.reset(new Texture());
|
||||
glBindTexture(GL_TEXTURE_2D, _billboardTexture->getID());
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 1,
|
||||
GL_BGRA, GL_UNSIGNED_BYTE, image.constBits());
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
} else {
|
||||
glBindTexture(GL_TEXTURE_2D, _billboardTexture->getID());
|
||||
}
|
||||
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_GREATER, 0.5f);
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(_position.x, _position.y, _position.z);
|
||||
|
||||
// rotate about vertical to face the camera
|
||||
glm::quat rotation = getOrientation();
|
||||
glm::vec3 cameraVector = glm::inverse(rotation) * (Application::getInstance()->getCamera()->getPosition() - _position);
|
||||
rotation = rotation * glm::angleAxis(glm::degrees(atan2f(-cameraVector.x, -cameraVector.z)), 0.0f, 1.0f, 0.0f);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z);
|
||||
|
||||
// compute the size from the billboard camera parameters and scale
|
||||
float size = _scale * BILLBOARD_DISTANCE * tanf(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f));
|
||||
glScalef(size, size, size);
|
||||
|
||||
glColor3f(1.0f, 1.0f, 1.0f);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0.0f, 0.0f);
|
||||
glVertex2f(-1.0f, -1.0f);
|
||||
glTexCoord2f(1.0f, 0.0f);
|
||||
glVertex2f(1.0f, -1.0f);
|
||||
glTexCoord2f(1.0f, 1.0f);
|
||||
glVertex2f(1.0f, 1.0f);
|
||||
glTexCoord2f(0.0f, 1.0f);
|
||||
glVertex2f(-1.0f, 1.0f);
|
||||
glEnd();
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glEnable(GL_LIGHTING);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
void Avatar::renderDisplayName() {
|
||||
|
||||
if (_displayName.isEmpty() || _displayNameAlpha == 0.0f) {
|
||||
|
@ -502,6 +565,13 @@ void Avatar::setDisplayName(const QString& displayName) {
|
|||
_displayNameBoundingRect = textRenderer(DISPLAYNAME)->metrics().tightBoundingRect(displayName);
|
||||
}
|
||||
|
||||
void Avatar::setBillboard(const QByteArray& billboard) {
|
||||
AvatarData::setBillboard(billboard);
|
||||
|
||||
// clear out any existing billboard texture
|
||||
_billboardTexture.reset();
|
||||
}
|
||||
|
||||
int Avatar::parseData(const QByteArray& packet) {
|
||||
// change in position implies movement
|
||||
glm::vec3 oldPosition = _position;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include <QtCore/QScopedPointer>
|
||||
#include <QtCore/QUuid>
|
||||
|
||||
#include <AvatarData.h>
|
||||
|
@ -62,6 +63,8 @@ enum ScreenTintLayer {
|
|||
// Grayson as he's building a street around here for demo dinner 2
|
||||
const glm::vec3 START_LOCATION(0.485f * TREE_SCALE, 0.f, 0.5f * TREE_SCALE);
|
||||
|
||||
class Texture;
|
||||
|
||||
class Avatar : public AvatarData {
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -87,6 +90,9 @@ public:
|
|||
Head* getHead() { return static_cast<Head*>(_headData); }
|
||||
Hand* getHand() { return static_cast<Hand*>(_handData); }
|
||||
glm::quat getWorldAlignedOrientation() const;
|
||||
|
||||
/// Returns the distance to use as a LOD parameter.
|
||||
float getLODDistance() const;
|
||||
|
||||
Node* getOwningAvatarMixer() { return _owningAvatarMixer.data(); }
|
||||
void setOwningAvatarMixer(const QWeakPointer<Node>& owningAvatarMixer) { _owningAvatarMixer = owningAvatarMixer; }
|
||||
|
@ -114,6 +120,7 @@ public:
|
|||
virtual void setFaceModelURL(const QUrl& faceModelURL);
|
||||
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
|
||||
virtual void setDisplayName(const QString& displayName);
|
||||
virtual void setBillboard(const QByteArray& billboard);
|
||||
|
||||
void setShowDisplayName(bool showDisplayName);
|
||||
|
||||
|
@ -167,8 +174,10 @@ protected:
|
|||
private:
|
||||
|
||||
bool _initialized;
|
||||
QScopedPointer<Texture> _billboardTexture;
|
||||
|
||||
void renderBody(bool forceRenderHead);
|
||||
void renderBillboard();
|
||||
|
||||
void renderDisplayName();
|
||||
};
|
||||
|
|
|
@ -133,6 +133,9 @@ void AvatarManager::processAvatarMixerDatagram(const QByteArray& datagram, const
|
|||
case PacketTypeAvatarIdentity:
|
||||
processAvatarIdentityPacket(datagram);
|
||||
break;
|
||||
case PacketTypeAvatarBillboard:
|
||||
processAvatarBillboardPacket(datagram);
|
||||
break;
|
||||
case PacketTypeKillAvatar:
|
||||
processKillAvatar(datagram);
|
||||
break;
|
||||
|
@ -212,6 +215,20 @@ void AvatarManager::processAvatarIdentityPacket(const QByteArray &packet) {
|
|||
}
|
||||
}
|
||||
|
||||
void AvatarManager::processAvatarBillboardPacket(const QByteArray& packet) {
|
||||
int headerSize = numBytesForPacketHeader(packet);
|
||||
QUuid nodeUUID = QUuid::fromRfc4122(QByteArray::fromRawData(packet.constData() + headerSize, NUM_BYTES_RFC4122_UUID));
|
||||
|
||||
AvatarSharedPointer matchingAvatar = _avatarHash.value(nodeUUID);
|
||||
if (matchingAvatar) {
|
||||
Avatar* avatar = static_cast<Avatar*>(matchingAvatar.data());
|
||||
QByteArray billboard = packet.mid(headerSize + NUM_BYTES_RFC4122_UUID);
|
||||
if (avatar->getBillboard() != billboard) {
|
||||
avatar->setBillboard(billboard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarManager::processKillAvatar(const QByteArray& datagram) {
|
||||
// read the node id
|
||||
QUuid nodeUUID = QUuid::fromRfc4122(datagram.mid(numBytesForPacketHeader(datagram), NUM_BYTES_RFC4122_UUID));
|
||||
|
|
|
@ -42,6 +42,7 @@ private:
|
|||
|
||||
void processAvatarDataPacket(const QByteArray& packet, const QWeakPointer<Node>& mixerWeakPointer);
|
||||
void processAvatarIdentityPacket(const QByteArray& packet);
|
||||
void processAvatarBillboardPacket(const QByteArray& packet);
|
||||
void processKillAvatar(const QByteArray& datagram);
|
||||
|
||||
void simulateAvatarFades(float deltaTime);
|
||||
|
|
|
@ -28,7 +28,6 @@ Head::Head(Avatar* owningAvatar) :
|
|||
_gravity(0.0f, -1.0f, 0.0f),
|
||||
_lastLoudness(0.0f),
|
||||
_audioAttack(0.0f),
|
||||
_bodyRotation(0.0f, 0.0f, 0.0f),
|
||||
_angularVelocity(0,0,0),
|
||||
_renderLookatVectors(false),
|
||||
_saccade(0.0f, 0.0f, 0.0f),
|
||||
|
@ -158,6 +157,9 @@ void Head::simulate(float deltaTime, bool isMine) {
|
|||
glm::clamp(sqrt(_averageLoudness * JAW_OPEN_SCALE) - JAW_OPEN_DEAD_ZONE, 0.0f, 1.0f), _blendshapeCoefficients);
|
||||
}
|
||||
|
||||
if (!isMine) {
|
||||
_faceModel.setLODDistance(static_cast<Avatar*>(_owningAvatar)->getLODDistance());
|
||||
}
|
||||
_faceModel.simulate(deltaTime);
|
||||
|
||||
// the blend face may have custom eye meshes
|
||||
|
@ -180,12 +182,8 @@ void Head::setScale (float scale) {
|
|||
_scale = scale;
|
||||
}
|
||||
|
||||
glm::quat Head::getOrientation() const {
|
||||
return glm::quat(glm::radians(_bodyRotation)) * glm::quat(glm::radians(glm::vec3(_pitch, _yaw, _roll)));
|
||||
}
|
||||
|
||||
glm::quat Head::getTweakedOrientation() const {
|
||||
return glm::quat(glm::radians(_bodyRotation)) * glm::quat(glm::radians(glm::vec3(getTweakedPitch(), getTweakedYaw(), getTweakedRoll() )));
|
||||
return _owningAvatar->getOrientation() * glm::quat(glm::radians(glm::vec3(getTweakedPitch(), getTweakedYaw(), getTweakedRoll() )));
|
||||
}
|
||||
|
||||
glm::quat Head::getCameraOrientation () const {
|
||||
|
|
|
@ -40,13 +40,11 @@ public:
|
|||
void render(float alpha);
|
||||
void setScale(float scale);
|
||||
void setPosition(glm::vec3 position) { _position = position; }
|
||||
void setBodyRotation(glm::vec3 bodyRotation) { _bodyRotation = bodyRotation; }
|
||||
void setGravity(glm::vec3 gravity) { _gravity = gravity; }
|
||||
void setAverageLoudness(float averageLoudness) { _averageLoudness = averageLoudness; }
|
||||
void setReturnToCenter (bool returnHeadToCenter) { _returnHeadToCenter = returnHeadToCenter; }
|
||||
void setRenderLookatVectors(bool onOff) { _renderLookatVectors = onOff; }
|
||||
|
||||
glm::quat getOrientation() const;
|
||||
glm::quat getTweakedOrientation() const;
|
||||
glm::quat getCameraOrientation () const;
|
||||
const glm::vec3& getAngularVelocity() const { return _angularVelocity; }
|
||||
|
@ -97,7 +95,6 @@ private:
|
|||
glm::vec3 _gravity;
|
||||
float _lastLoudness;
|
||||
float _audioAttack;
|
||||
glm::vec3 _bodyRotation;
|
||||
glm::vec3 _angularVelocity;
|
||||
bool _renderLookatVectors;
|
||||
glm::vec3 _saccade;
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include <QBuffer>
|
||||
|
||||
#include <glm/gtx/vector_angle.hpp>
|
||||
|
||||
#include <NodeList.h>
|
||||
|
@ -57,7 +59,8 @@ MyAvatar::MyAvatar() :
|
|||
_thrustMultiplier(1.0f),
|
||||
_moveTarget(0,0,0),
|
||||
_moveTargetStepCounter(0),
|
||||
_lookAtTargetAvatar()
|
||||
_lookAtTargetAvatar(),
|
||||
_billboardValid(false)
|
||||
{
|
||||
for (int i = 0; i < MAX_DRIVE_KEYS; i++) {
|
||||
_driveKeys[i] = 0.0f;
|
||||
|
@ -321,7 +324,6 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
_skeletonModel.simulate(deltaTime);
|
||||
|
||||
Head* head = getHead();
|
||||
head->setBodyRotation(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll));
|
||||
glm::vec3 headPosition;
|
||||
if (!_skeletonModel.getHeadPosition(headPosition)) {
|
||||
headPosition = _position;
|
||||
|
@ -332,7 +334,9 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
|
||||
// Zero thrust out now that we've added it to velocity in this frame
|
||||
_thrust = glm::vec3(0, 0, 0);
|
||||
|
||||
|
||||
// consider updating our billboard
|
||||
maybeUpdateBillboard();
|
||||
}
|
||||
|
||||
const float MAX_PITCH = 90.0f;
|
||||
|
@ -705,6 +709,16 @@ glm::vec3 MyAvatar::getUprightHeadPosition() const {
|
|||
return _position + getWorldAlignedOrientation() * glm::vec3(0.0f, getPelvisToHeadLength(), 0.0f);
|
||||
}
|
||||
|
||||
void MyAvatar::setFaceModelURL(const QUrl& faceModelURL) {
|
||||
Avatar::setFaceModelURL(faceModelURL);
|
||||
_billboardValid = false;
|
||||
}
|
||||
|
||||
void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||
Avatar::setSkeletonModelURL(skeletonModelURL);
|
||||
_billboardValid = false;
|
||||
}
|
||||
|
||||
void MyAvatar::renderBody(bool forceRenderHead) {
|
||||
// Render the body's voxels and head
|
||||
_skeletonModel.render(1.0f);
|
||||
|
@ -1124,6 +1138,20 @@ void MyAvatar::updateChatCircle(float deltaTime) {
|
|||
_position = glm::mix(_position, targetPosition, APPROACH_RATE);
|
||||
}
|
||||
|
||||
void MyAvatar::maybeUpdateBillboard() {
|
||||
if (_billboardValid || !(_skeletonModel.isLoadedWithTextures() && getHead()->getFaceModel().isLoadedWithTextures())) {
|
||||
return;
|
||||
}
|
||||
QImage image = Application::getInstance()->renderAvatarBillboard();
|
||||
_billboard.clear();
|
||||
QBuffer buffer(&_billboard);
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
image.save(&buffer, "PNG");
|
||||
_billboardValid = true;
|
||||
|
||||
sendBillboardPacket();
|
||||
}
|
||||
|
||||
void MyAvatar::setGravity(glm::vec3 gravity) {
|
||||
_gravity = gravity;
|
||||
getHead()->setGravity(_gravity);
|
||||
|
|
|
@ -84,6 +84,9 @@ public:
|
|||
void updateLookAtTargetAvatar(glm::vec3& eyePosition);
|
||||
void clearLookAtTargetAvatar();
|
||||
|
||||
virtual void setFaceModelURL(const QUrl& faceModelURL);
|
||||
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
|
||||
|
||||
public slots:
|
||||
void goHome();
|
||||
void increaseSize();
|
||||
|
@ -118,6 +121,8 @@ private:
|
|||
glm::vec3 _transmitterPickStart;
|
||||
glm::vec3 _transmitterPickEnd;
|
||||
|
||||
bool _billboardValid;
|
||||
|
||||
// private methods
|
||||
void renderBody(bool forceRenderHead);
|
||||
void updateThrust(float deltaTime);
|
||||
|
@ -128,6 +133,7 @@ private:
|
|||
void applyHardCollision(const glm::vec3& penetration, float elasticity, float damping);
|
||||
void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency);
|
||||
void updateChatCircle(float deltaTime);
|
||||
void maybeUpdateBillboard();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -17,8 +17,8 @@ using namespace std;
|
|||
|
||||
Model::Model(QObject* parent) :
|
||||
QObject(parent),
|
||||
_pupilDilation(0.0f)
|
||||
{
|
||||
_lodDistance(0.0f),
|
||||
_pupilDilation(0.0f) {
|
||||
// we may have been created in the network thread, but we live in the main thread
|
||||
moveToThread(Application::getInstance()->thread());
|
||||
}
|
||||
|
@ -46,6 +46,21 @@ void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locati
|
|||
program.release();
|
||||
}
|
||||
|
||||
bool Model::isLoadedWithTextures() const {
|
||||
if (!isActive()) {
|
||||
return false;
|
||||
}
|
||||
foreach (const NetworkMesh& mesh, _geometry->getMeshes()) {
|
||||
foreach (const NetworkMeshPart& part, mesh.parts) {
|
||||
if (part.diffuseTexture && !part.diffuseTexture->isLoaded() ||
|
||||
part.normalTexture && !part.normalTexture->isLoaded()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Model::init() {
|
||||
if (!_program.isLinked()) {
|
||||
switchToResourcesParentIfRequired();
|
||||
|
@ -92,8 +107,7 @@ void Model::reset() {
|
|||
void Model::simulate(float deltaTime) {
|
||||
// update our LOD
|
||||
if (_geometry) {
|
||||
QSharedPointer<NetworkGeometry> geometry = _geometry->getLODOrFallback(glm::distance(_translation,
|
||||
Application::getInstance()->getCamera()->getPosition()), _lodHysteresis);
|
||||
QSharedPointer<NetworkGeometry> geometry = _geometry->getLODOrFallback(_lodDistance, _lodHysteresis);
|
||||
if (_geometry != geometry) {
|
||||
deleteGeometry();
|
||||
_dilatedTextures.clear();
|
||||
|
|
|
@ -46,6 +46,8 @@ public:
|
|||
|
||||
bool isActive() const { return _geometry && _geometry->isLoaded(); }
|
||||
|
||||
bool isLoadedWithTextures() const;
|
||||
|
||||
void init();
|
||||
void reset();
|
||||
void simulate(float deltaTime);
|
||||
|
@ -54,6 +56,9 @@ public:
|
|||
Q_INVOKABLE void setURL(const QUrl& url, const QUrl& fallback = QUrl());
|
||||
const QUrl& getURL() const { return _url; }
|
||||
|
||||
/// Sets the distance parameter used for LOD computations.
|
||||
void setLODDistance(float distance) { _lodDistance = distance; }
|
||||
|
||||
/// Returns the extents of the model in its bind pose.
|
||||
Extents getBindExtents() const;
|
||||
|
||||
|
@ -228,13 +233,14 @@ private:
|
|||
void renderMeshes(float alpha, bool translucent);
|
||||
|
||||
QSharedPointer<NetworkGeometry> _baseGeometry; ///< reference required to prevent collection of base
|
||||
float _lodDistance;
|
||||
float _lodHysteresis;
|
||||
|
||||
float _pupilDilation;
|
||||
std::vector<float> _blendshapeCoefficients;
|
||||
|
||||
QUrl _url;
|
||||
|
||||
|
||||
QVector<GLuint> _blendedVertexBufferIDs;
|
||||
QVector<QVector<QSharedPointer<Texture> > > _dilatedTextures;
|
||||
bool _resetStates;
|
||||
|
|
|
@ -258,9 +258,11 @@ NetworkTexture::NetworkTexture(const QUrl& url, bool normalMap) :
|
|||
_reply(NULL),
|
||||
_attempts(0),
|
||||
_averageColor(1.0f, 1.0f, 1.0f, 1.0f),
|
||||
_translucent(false) {
|
||||
_translucent(false),
|
||||
_loaded(false) {
|
||||
|
||||
if (!url.isValid()) {
|
||||
_loaded = true;
|
||||
return;
|
||||
}
|
||||
_request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
|
||||
|
@ -298,6 +300,7 @@ void NetworkTexture::handleDownloadProgress(qint64 bytesReceived, qint64 bytesTo
|
|||
_reply->disconnect(this);
|
||||
_reply->deleteLater();
|
||||
_reply = NULL;
|
||||
_loaded = true;
|
||||
|
||||
QImage image = QImage::fromData(entirety).convertToFormat(QImage::Format_ARGB32);
|
||||
|
||||
|
@ -345,6 +348,8 @@ void NetworkTexture::handleReplyError() {
|
|||
QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, SLOT(makeRequest()));
|
||||
debug << " -- retrying...";
|
||||
|
||||
} else {
|
||||
_loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -118,6 +118,8 @@ public:
|
|||
NetworkTexture(const QUrl& url, bool normalMap);
|
||||
~NetworkTexture();
|
||||
|
||||
bool isLoaded() const { return _loaded; }
|
||||
|
||||
/// Returns the average color over the entire texture.
|
||||
const glm::vec4& getAverageColor() const { return _averageColor; }
|
||||
|
||||
|
@ -142,6 +144,7 @@ private:
|
|||
int _attempts;
|
||||
glm::vec4 _averageColor;
|
||||
bool _translucent;
|
||||
bool _loaded;
|
||||
};
|
||||
|
||||
/// Caches derived, dilated textures.
|
||||
|
|
50
interface/src/ui/ClipboardOverlay.cpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
//
|
||||
// ClipboardOverlay.cpp
|
||||
// hifi
|
||||
//
|
||||
// Created by Clément Brisset on 2/20/14.
|
||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
// include this before QGLWidget, which includes an earlier version of OpenGL
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <QGLWidget>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "ClipboardOverlay.h"
|
||||
#include "../Application.h"
|
||||
|
||||
static int lastVoxelCount = 0;
|
||||
|
||||
ClipboardOverlay::ClipboardOverlay() {
|
||||
}
|
||||
|
||||
ClipboardOverlay::~ClipboardOverlay() {
|
||||
}
|
||||
|
||||
void ClipboardOverlay::render() {
|
||||
if (!_visible) {
|
||||
return; // do nothing if we're not visible
|
||||
}
|
||||
|
||||
VoxelSystem* voxelSystem = Application::getInstance()->getSharedVoxelSystem();
|
||||
VoxelTree* clipboard = Application::getInstance()->getClipboard();
|
||||
if (voxelSystem->getTree() != clipboard) {
|
||||
voxelSystem->changeTree(clipboard);
|
||||
}
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(_position.x, _position.y, _position.z);
|
||||
glScalef(_size, _size, _size);
|
||||
|
||||
// We only force the redraw when the clipboard content has changed
|
||||
if (lastVoxelCount != clipboard->getOctreeElementsCount()) {
|
||||
voxelSystem->forceRedrawEntireTree();
|
||||
lastVoxelCount = clipboard->getOctreeElementsCount();
|
||||
}
|
||||
|
||||
voxelSystem->render();
|
||||
|
||||
glPopMatrix();
|
||||
}
|
25
interface/src/ui/ClipboardOverlay.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// ClipboardOverlay.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Clément Brisset on 2/20/14.
|
||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__ClipboardOverlay__
|
||||
#define __interface__ClipboardOverlay__
|
||||
|
||||
#include "Volume3DOverlay.h"
|
||||
|
||||
class ClipboardOverlay : public Volume3DOverlay {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ClipboardOverlay();
|
||||
~ClipboardOverlay();
|
||||
|
||||
virtual void render();
|
||||
};
|
||||
|
||||
|
||||
#endif /* defined(__interface__ClipboardOverlay__) */
|
|
@ -12,7 +12,7 @@
|
|||
#include "Overlays.h"
|
||||
#include "Sphere3DOverlay.h"
|
||||
#include "TextOverlay.h"
|
||||
|
||||
#include "ClipboardOverlay.h"
|
||||
|
||||
unsigned int Overlays::_nextOverlayID = 1;
|
||||
|
||||
|
@ -73,6 +73,12 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope
|
|||
thisOverlay->setProperties(properties);
|
||||
created = true;
|
||||
is3D = true;
|
||||
} else if (type == "clipboard") {
|
||||
thisOverlay = new ClipboardOverlay();
|
||||
thisOverlay->init(_parent);
|
||||
thisOverlay->setProperties(properties);
|
||||
created = true;
|
||||
is3D = true;
|
||||
}
|
||||
|
||||
if (created) {
|
||||
|
|
|
@ -305,6 +305,15 @@ QByteArray AvatarData::identityByteArray() {
|
|||
return identityData;
|
||||
}
|
||||
|
||||
bool AvatarData::hasBillboardChangedAfterParsing(const QByteArray& packet) {
|
||||
QByteArray newBillboard = packet.mid(numBytesForPacketHeader(packet));
|
||||
if (newBillboard == _billboard) {
|
||||
return false;
|
||||
}
|
||||
_billboard = newBillboard;
|
||||
return true;
|
||||
}
|
||||
|
||||
void AvatarData::setFaceModelURL(const QUrl& faceModelURL) {
|
||||
_faceModelURL = faceModelURL.isEmpty() ? DEFAULT_HEAD_MODEL_URL : faceModelURL;
|
||||
|
||||
|
@ -323,6 +332,12 @@ void AvatarData::setDisplayName(const QString& displayName) {
|
|||
qDebug() << "Changing display name for avatar to" << displayName;
|
||||
}
|
||||
|
||||
void AvatarData::setBillboard(const QByteArray& billboard) {
|
||||
_billboard = billboard;
|
||||
|
||||
qDebug() << "Changing billboard for avatar.";
|
||||
}
|
||||
|
||||
void AvatarData::setClampedTargetScale(float targetScale) {
|
||||
|
||||
targetScale = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE);
|
||||
|
@ -344,3 +359,10 @@ void AvatarData::sendIdentityPacket() {
|
|||
|
||||
NodeList::getInstance()->broadcastToNodes(identityPacket, NodeSet() << NodeType::AvatarMixer);
|
||||
}
|
||||
|
||||
void AvatarData::sendBillboardPacket() {
|
||||
QByteArray billboardPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarBillboard);
|
||||
billboardPacket.append(_billboard);
|
||||
|
||||
NodeList::getInstance()->broadcastToNodes(billboardPacket, NodeSet() << NodeType::AvatarMixer);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ typedef unsigned long long quint64;
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QUuid>
|
||||
|
@ -54,6 +55,7 @@ static const float MIN_AVATAR_SCALE = .005f;
|
|||
const float MAX_AUDIO_LOUDNESS = 1000.0; // close enough for mouth animation
|
||||
|
||||
const int AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS = 1000;
|
||||
const int AVATAR_BILLBOARD_PACKET_SEND_INTERVAL_MSECS = 5000;
|
||||
|
||||
const QUrl DEFAULT_HEAD_MODEL_URL = QUrl("http://public.highfidelity.io/meshes/defaultAvatar_head.fst");
|
||||
const QUrl DEFAULT_BODY_MODEL_URL = QUrl("http://public.highfidelity.io/meshes/defaultAvatar_body.fst");
|
||||
|
@ -78,6 +80,7 @@ class AvatarData : public NodeData {
|
|||
Q_PROPERTY(QString chatMessage READ getQStringChatMessage WRITE setChatMessage)
|
||||
|
||||
Q_PROPERTY(glm::quat orientation READ getOrientation WRITE setOrientation)
|
||||
Q_PROPERTY(glm::quat headOrientation READ getHeadOrientation WRITE setHeadOrientation)
|
||||
Q_PROPERTY(float headPitch READ getHeadPitch WRITE setHeadPitch)
|
||||
|
||||
Q_PROPERTY(float audioLoudness READ getAudioLoudness WRITE setAudioLoudness)
|
||||
|
@ -109,6 +112,9 @@ public:
|
|||
glm::quat getOrientation() const { return glm::quat(glm::radians(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll))); }
|
||||
void setOrientation(const glm::quat& orientation);
|
||||
|
||||
glm::quat getHeadOrientation() const { return _headData->getOrientation(); }
|
||||
void setHeadOrientation(const glm::quat& orientation) { _headData->setOrientation(orientation); }
|
||||
|
||||
// access to Head().set/getMousePitch
|
||||
float getHeadPitch() const { return _headData->getPitch(); }
|
||||
void setHeadPitch(float value) { _headData->setPitch(value); };
|
||||
|
@ -151,6 +157,8 @@ public:
|
|||
bool hasIdentityChangedAfterParsing(const QByteArray& packet);
|
||||
QByteArray identityByteArray();
|
||||
|
||||
bool hasBillboardChangedAfterParsing(const QByteArray& packet);
|
||||
|
||||
const QUrl& getFaceModelURL() const { return _faceModelURL; }
|
||||
QString getFaceModelURLString() const { return _faceModelURL.toString(); }
|
||||
const QUrl& getSkeletonModelURL() const { return _skeletonModelURL; }
|
||||
|
@ -159,6 +167,9 @@ public:
|
|||
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
|
||||
virtual void setDisplayName(const QString& displayName);
|
||||
|
||||
virtual void setBillboard(const QByteArray& billboard);
|
||||
const QByteArray& getBillboard() const { return _billboard; }
|
||||
|
||||
QString getFaceModelURLFromScript() const { return _faceModelURL.toString(); }
|
||||
void setFaceModelURLFromScript(const QString& faceModelString) { setFaceModelURL(faceModelString); }
|
||||
|
||||
|
@ -169,6 +180,7 @@ public:
|
|||
|
||||
public slots:
|
||||
void sendIdentityPacket();
|
||||
void sendBillboardPacket();
|
||||
|
||||
protected:
|
||||
glm::vec3 _position;
|
||||
|
@ -204,6 +216,8 @@ protected:
|
|||
float _displayNameTargetAlpha;
|
||||
float _displayNameAlpha;
|
||||
|
||||
QByteArray _billboard;
|
||||
|
||||
private:
|
||||
// privatize the copy constructor and assignment operator so they cannot be called
|
||||
AvatarData(const AvatarData&);
|
||||
|
|
|
@ -6,6 +6,11 @@
|
|||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
#include <OctreeConstants.h>
|
||||
|
||||
#include "AvatarData.h"
|
||||
#include "HeadData.h"
|
||||
|
||||
HeadData::HeadData(AvatarData* owningAvatar) :
|
||||
|
@ -26,6 +31,24 @@ HeadData::HeadData(AvatarData* owningAvatar) :
|
|||
|
||||
}
|
||||
|
||||
glm::quat HeadData::getOrientation() const {
|
||||
return _owningAvatar->getOrientation() * glm::quat(glm::radians(glm::vec3(_pitch, _yaw, _roll)));
|
||||
}
|
||||
|
||||
void HeadData::setOrientation(const glm::quat& orientation) {
|
||||
// rotate body about vertical axis
|
||||
glm::quat bodyOrientation = _owningAvatar->getOrientation();
|
||||
glm::vec3 newFront = glm::inverse(bodyOrientation) * (orientation * IDENTITY_FRONT);
|
||||
bodyOrientation = bodyOrientation * glm::angleAxis(glm::degrees(atan2f(-newFront.x, -newFront.z)), 0.0f, 1.0f, 0.0f);
|
||||
_owningAvatar->setOrientation(bodyOrientation);
|
||||
|
||||
// the rest goes to the head
|
||||
glm::vec3 eulers = safeEulerAngles(glm::inverse(bodyOrientation) * orientation);
|
||||
_pitch = eulers.x;
|
||||
_yaw = eulers.y;
|
||||
_roll = eulers.z;
|
||||
}
|
||||
|
||||
void HeadData::addYaw(float yaw) {
|
||||
setYaw(_yaw + yaw);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
const float MIN_HEAD_YAW = -110;
|
||||
const float MAX_HEAD_YAW = 110;
|
||||
|
@ -42,6 +43,9 @@ public:
|
|||
float getRoll() const { return _roll; }
|
||||
void setRoll(float roll) { _roll = glm::clamp(roll, MIN_HEAD_ROLL, MAX_HEAD_ROLL); }
|
||||
|
||||
glm::quat getOrientation() const;
|
||||
void setOrientation(const glm::quat& orientation);
|
||||
|
||||
float getAudioLoudness() const { return _audioLoudness; }
|
||||
void setAudioLoudness(float audioLoudness) { _audioLoudness = audioLoudness; }
|
||||
|
||||
|
|
|
@ -53,7 +53,8 @@ enum PacketType {
|
|||
PacketTypeParticleErase,
|
||||
PacketTypeParticleAddResponse,
|
||||
PacketTypeMetavoxelData,
|
||||
PacketTypeAvatarIdentity
|
||||
PacketTypeAvatarIdentity,
|
||||
PacketTypeAvatarBillboard
|
||||
};
|
||||
|
||||
typedef char PacketVersion;
|
||||
|
|