mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-05 21:50:02 +02:00
Merge branch 'master' of https://github.com/worklist/hifi into 19483
This commit is contained in:
commit
11bf9b8a50
10 changed files with 928 additions and 876 deletions
|
@ -18,6 +18,7 @@
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
#include <UUID.h>
|
#include <UUID.h>
|
||||||
#include <VoxelConstants.h>
|
#include <VoxelConstants.h>
|
||||||
|
#include <ParticlesScriptingInterface.h>
|
||||||
|
|
||||||
#include "Agent.h"
|
#include "Agent.h"
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -27,19 +27,19 @@ OctreeSendThread::OctreeSendThread(const QUuid& nodeUUID, OctreeServer* myServer
|
||||||
bool OctreeSendThread::process() {
|
bool OctreeSendThread::process() {
|
||||||
uint64_t start = usecTimestampNow();
|
uint64_t start = usecTimestampNow();
|
||||||
bool gotLock = false;
|
bool gotLock = false;
|
||||||
|
|
||||||
// don't do any send processing until the initial load of the octree is complete...
|
// don't do any send processing until the initial load of the octree is complete...
|
||||||
if (_myServer->isInitialLoadComplete()) {
|
if (_myServer->isInitialLoadComplete()) {
|
||||||
Node* node = NodeList::getInstance()->nodeWithUUID(_nodeUUID);
|
Node* node = NodeList::getInstance()->nodeWithUUID(_nodeUUID);
|
||||||
|
|
||||||
if (node) {
|
if (node) {
|
||||||
// make sure the node list doesn't kill our node while we're using it
|
// make sure the node list doesn't kill our node while we're using it
|
||||||
if (node->trylock()) {
|
if (node->trylock()) {
|
||||||
gotLock = true;
|
gotLock = true;
|
||||||
OctreeQueryNode* nodeData = NULL;
|
OctreeQueryNode* nodeData = NULL;
|
||||||
|
|
||||||
nodeData = (OctreeQueryNode*) node->getLinkedData();
|
nodeData = (OctreeQueryNode*) node->getLinkedData();
|
||||||
|
|
||||||
int packetsSent = 0;
|
int packetsSent = 0;
|
||||||
|
|
||||||
// Sometimes the node data has not yet been linked, in which case we can't really do anything
|
// Sometimes the node data has not yet been linked, in which case we can't really do anything
|
||||||
|
@ -50,7 +50,7 @@ bool OctreeSendThread::process() {
|
||||||
}
|
}
|
||||||
packetsSent = packetDistributor(node, nodeData, viewFrustumChanged);
|
packetsSent = packetDistributor(node, nodeData, viewFrustumChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
node->unlock(); // we're done with this node for now.
|
node->unlock(); // we're done with this node for now.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ bool OctreeSendThread::process() {
|
||||||
qDebug("OctreeSendThread::process() waiting for isInitialLoadComplete()\n");
|
qDebug("OctreeSendThread::process() waiting for isInitialLoadComplete()\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only sleep if we're still running and we got the lock last time we tried, otherwise try to get the lock asap
|
// Only sleep if we're still running and we got the lock last time we tried, otherwise try to get the lock asap
|
||||||
if (isStillRunning() && gotLock) {
|
if (isStillRunning() && gotLock) {
|
||||||
// dynamically sleep until we need to fire off the next set of octree elements
|
// dynamically sleep until we need to fire off the next set of octree elements
|
||||||
|
@ -99,14 +99,14 @@ int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, in
|
||||||
nodeData->resetOctreePacket(true); // we still need to reset it though!
|
nodeData->resetOctreePacket(true); // we still need to reset it though!
|
||||||
return packetsSent; // without sending...
|
return packetsSent; // without sending...
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned char* messageData = nodeData->getPacket();
|
const unsigned char* messageData = nodeData->getPacket();
|
||||||
int numBytesPacketHeader = numBytesForPacketHeader(messageData);
|
int numBytesPacketHeader = numBytesForPacketHeader(messageData);
|
||||||
const unsigned char* dataAt = messageData + numBytesPacketHeader;
|
const unsigned char* dataAt = messageData + numBytesPacketHeader;
|
||||||
dataAt += sizeof(OCTREE_PACKET_FLAGS);
|
dataAt += sizeof(OCTREE_PACKET_FLAGS);
|
||||||
OCTREE_PACKET_SEQUENCE sequence = (*(OCTREE_PACKET_SEQUENCE*)dataAt);
|
OCTREE_PACKET_SEQUENCE sequence = (*(OCTREE_PACKET_SEQUENCE*)dataAt);
|
||||||
dataAt += sizeof(OCTREE_PACKET_SEQUENCE);
|
dataAt += sizeof(OCTREE_PACKET_SEQUENCE);
|
||||||
|
|
||||||
|
|
||||||
// If we've got a stats message ready to send, then see if we can piggyback them together
|
// If we've got a stats message ready to send, then see if we can piggyback them together
|
||||||
if (nodeData->stats.isReadyToSend()) {
|
if (nodeData->stats.isReadyToSend()) {
|
||||||
|
@ -126,13 +126,14 @@ int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, in
|
||||||
int thisWastedBytes = 0;
|
int thisWastedBytes = 0;
|
||||||
_totalWastedBytes += thisWastedBytes;
|
_totalWastedBytes += thisWastedBytes;
|
||||||
_totalBytes += nodeData->getPacketLength();
|
_totalBytes += nodeData->getPacketLength();
|
||||||
_totalPackets++;
|
_totalPackets++;
|
||||||
if (debug) {
|
if (debug) {
|
||||||
qDebug() << "Adding stats to packet at " << now << " [" << _totalPackets <<"]: sequence: " << sequence <<
|
qDebug() << "Adding stats to packet at " << now << " [" << _totalPackets <<"]: sequence: " << sequence <<
|
||||||
" size: " << nodeData->getPacketLength() << " [" << _totalBytes <<
|
" statsMessageLength: " << statsMessageLength <<
|
||||||
|
" original size: " << nodeData->getPacketLength() << " [" << _totalBytes <<
|
||||||
"] wasted bytes:" << thisWastedBytes << " [" << _totalWastedBytes << "]\n";
|
"] wasted bytes:" << thisWastedBytes << " [" << _totalWastedBytes << "]\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
// actually send it
|
// actually send it
|
||||||
NodeList::getInstance()->getNodeSocket().writeDatagram((char*) statsMessage, statsMessageLength,
|
NodeList::getInstance()->getNodeSocket().writeDatagram((char*) statsMessage, statsMessageLength,
|
||||||
node->getActiveSocket()->getAddress(),
|
node->getActiveSocket()->getAddress(),
|
||||||
|
@ -151,7 +152,7 @@ int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, in
|
||||||
_totalBytes += statsMessageLength;
|
_totalBytes += statsMessageLength;
|
||||||
_totalPackets++;
|
_totalPackets++;
|
||||||
if (debug) {
|
if (debug) {
|
||||||
qDebug() << "Sending separate stats packet at " << now << " [" << _totalPackets <<"]: sequence: " << sequence <<
|
qDebug() << "Sending separate stats packet at " << now << " [" << _totalPackets <<"]: sequence: " << sequence <<
|
||||||
" size: " << statsMessageLength << " [" << _totalBytes <<
|
" size: " << statsMessageLength << " [" << _totalBytes <<
|
||||||
"] wasted bytes:" << thisWastedBytes << " [" << _totalWastedBytes << "]\n";
|
"] wasted bytes:" << thisWastedBytes << " [" << _totalWastedBytes << "]\n";
|
||||||
}
|
}
|
||||||
|
@ -171,7 +172,7 @@ int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, in
|
||||||
_totalBytes += nodeData->getPacketLength();
|
_totalBytes += nodeData->getPacketLength();
|
||||||
_totalPackets++;
|
_totalPackets++;
|
||||||
if (debug) {
|
if (debug) {
|
||||||
qDebug() << "Sending packet at " << now << " [" << _totalPackets <<"]: sequence: " << sequence <<
|
qDebug() << "Sending packet at " << now << " [" << _totalPackets <<"]: sequence: " << sequence <<
|
||||||
" size: " << nodeData->getPacketLength() << " [" << _totalBytes <<
|
" size: " << nodeData->getPacketLength() << " [" << _totalBytes <<
|
||||||
"] wasted bytes:" << thisWastedBytes << " [" << _totalWastedBytes << "]\n";
|
"] wasted bytes:" << thisWastedBytes << " [" << _totalWastedBytes << "]\n";
|
||||||
}
|
}
|
||||||
|
@ -191,7 +192,7 @@ int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, in
|
||||||
_totalBytes += nodeData->getPacketLength();
|
_totalBytes += nodeData->getPacketLength();
|
||||||
_totalPackets++;
|
_totalPackets++;
|
||||||
if (debug) {
|
if (debug) {
|
||||||
qDebug() << "Sending packet at " << now << " [" << _totalPackets <<"]: sequence: " << sequence <<
|
qDebug() << "Sending packet at " << now << " [" << _totalPackets <<"]: sequence: " << sequence <<
|
||||||
" size: " << nodeData->getPacketLength() << " [" << _totalBytes <<
|
" size: " << nodeData->getPacketLength() << " [" << _totalBytes <<
|
||||||
"] wasted bytes:" << thisWastedBytes << " [" << _totalWastedBytes << "]\n";
|
"] wasted bytes:" << thisWastedBytes << " [" << _totalWastedBytes << "]\n";
|
||||||
}
|
}
|
||||||
|
@ -205,12 +206,13 @@ int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, in
|
||||||
packetsSent++;
|
packetsSent++;
|
||||||
nodeData->resetOctreePacket();
|
nodeData->resetOctreePacket();
|
||||||
}
|
}
|
||||||
|
|
||||||
return packetsSent;
|
return packetsSent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Version of voxel distributor that sends the deepest LOD level at once
|
/// Version of voxel distributor that sends the deepest LOD level at once
|
||||||
int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, bool viewFrustumChanged) {
|
int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, bool viewFrustumChanged) {
|
||||||
|
bool forceDebugging = false;
|
||||||
|
|
||||||
int truePacketsSent = 0;
|
int truePacketsSent = 0;
|
||||||
int trueBytesSent = 0;
|
int trueBytesSent = 0;
|
||||||
|
@ -220,29 +222,32 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
|
||||||
// FOR NOW... node tells us if it wants to receive only view frustum deltas
|
// FOR NOW... node tells us if it wants to receive only view frustum deltas
|
||||||
bool wantDelta = viewFrustumChanged && nodeData->getWantDelta();
|
bool wantDelta = viewFrustumChanged && nodeData->getWantDelta();
|
||||||
|
|
||||||
// If our packet already has content in it, then we must use the color choice of the waiting packet.
|
// If our packet already has content in it, then we must use the color choice of the waiting packet.
|
||||||
// If we're starting a fresh packet, then...
|
// If we're starting a fresh packet, then...
|
||||||
// If we're moving, and the client asked for low res, then we force monochrome, otherwise, use
|
// If we're moving, and the client asked for low res, then we force monochrome, otherwise, use
|
||||||
// the clients requested color state.
|
// the clients requested color state.
|
||||||
bool wantColor = nodeData->getWantColor();
|
bool wantColor = nodeData->getWantColor();
|
||||||
bool wantCompression = nodeData->getWantCompression();
|
bool wantCompression = nodeData->getWantCompression();
|
||||||
|
|
||||||
// If we have a packet waiting, and our desired want color, doesn't match the current waiting packets color
|
// If we have a packet waiting, and our desired want color, doesn't match the current waiting packets color
|
||||||
// then let's just send that waiting packet.
|
// then let's just send that waiting packet.
|
||||||
if (!nodeData->getCurrentPacketFormatMatches()) {
|
if (!nodeData->getCurrentPacketFormatMatches()) {
|
||||||
if (nodeData->isPacketWaiting()) {
|
if (nodeData->isPacketWaiting()) {
|
||||||
if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
|
if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) {
|
||||||
printf("wantColor=%s wantCompression=%s SENDING PARTIAL PACKET! currentPacketIsColor=%s currentPacketIsCompressed=%s\n",
|
qDebug("about to call handlePacketSend() .... line: %d -- format change "
|
||||||
|
"wantColor=%s wantCompression=%s SENDING PARTIAL PACKET! currentPacketIsColor=%s "
|
||||||
|
"currentPacketIsCompressed=%s\n",
|
||||||
|
__LINE__,
|
||||||
debug::valueOf(wantColor), debug::valueOf(wantCompression),
|
debug::valueOf(wantColor), debug::valueOf(wantCompression),
|
||||||
debug::valueOf(nodeData->getCurrentPacketIsColor()),
|
debug::valueOf(nodeData->getCurrentPacketIsColor()),
|
||||||
debug::valueOf(nodeData->getCurrentPacketIsCompressed()) );
|
debug::valueOf(nodeData->getCurrentPacketIsCompressed()) );
|
||||||
}
|
}
|
||||||
packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
|
packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
|
||||||
} else {
|
} else {
|
||||||
if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
|
if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) {
|
||||||
printf("wantColor=%s wantCompression=%s FIXING HEADER! currentPacketIsColor=%s currentPacketIsCompressed=%s\n",
|
qDebug("wantColor=%s wantCompression=%s FIXING HEADER! currentPacketIsColor=%s currentPacketIsCompressed=%s\n",
|
||||||
debug::valueOf(wantColor), debug::valueOf(wantCompression),
|
debug::valueOf(wantColor), debug::valueOf(wantCompression),
|
||||||
debug::valueOf(nodeData->getCurrentPacketIsColor()),
|
debug::valueOf(nodeData->getCurrentPacketIsColor()),
|
||||||
debug::valueOf(nodeData->getCurrentPacketIsCompressed()) );
|
debug::valueOf(nodeData->getCurrentPacketIsCompressed()) );
|
||||||
}
|
}
|
||||||
nodeData->resetOctreePacket();
|
nodeData->resetOctreePacket();
|
||||||
|
@ -252,57 +257,57 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
|
||||||
targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE);
|
targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE);
|
||||||
}
|
}
|
||||||
if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
|
if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
|
||||||
printf("line:%d _packetData.changeSettings() wantCompression=%s targetSize=%d\n",__LINE__,
|
qDebug("line:%d _packetData.changeSettings() wantCompression=%s targetSize=%d\n", __LINE__,
|
||||||
debug::valueOf(wantCompression), targetSize);
|
debug::valueOf(wantCompression), targetSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
_packetData.changeSettings(wantCompression, targetSize);
|
_packetData.changeSettings(wantCompression, targetSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
|
if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
|
||||||
printf("wantColor/isColor=%s/%s wantCompression/isCompressed=%s/%s viewFrustumChanged=%s, getWantLowResMoving()=%s\n",
|
qDebug("wantColor/isColor=%s/%s wantCompression/isCompressed=%s/%s viewFrustumChanged=%s, getWantLowResMoving()=%s\n",
|
||||||
debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()),
|
debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()),
|
||||||
debug::valueOf(wantCompression), debug::valueOf(nodeData->getCurrentPacketIsCompressed()),
|
debug::valueOf(wantCompression), debug::valueOf(nodeData->getCurrentPacketIsCompressed()),
|
||||||
debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->getWantLowResMoving()));
|
debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->getWantLowResMoving()));
|
||||||
}
|
}
|
||||||
|
|
||||||
const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL;
|
const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL;
|
||||||
|
|
||||||
if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
|
if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) {
|
||||||
printf("packetDistributor() viewFrustumChanged=%s, nodeBag.isEmpty=%s, viewSent=%s\n",
|
qDebug("packetDistributor() viewFrustumChanged=%s, nodeBag.isEmpty=%s, viewSent=%s\n",
|
||||||
debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty()),
|
debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty()),
|
||||||
debug::valueOf(nodeData->getViewSent())
|
debug::valueOf(nodeData->getViewSent())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the current view frustum has changed OR we have nothing to send, then search against
|
// If the current view frustum has changed OR we have nothing to send, then search against
|
||||||
// the current view frustum for things to send.
|
// the current view frustum for things to send.
|
||||||
if (viewFrustumChanged || nodeData->nodeBag.isEmpty()) {
|
if (viewFrustumChanged || nodeData->nodeBag.isEmpty()) {
|
||||||
uint64_t now = usecTimestampNow();
|
uint64_t now = usecTimestampNow();
|
||||||
if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
|
if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) {
|
||||||
printf("(viewFrustumChanged=%s || nodeData->nodeBag.isEmpty() =%s)...\n",
|
qDebug("(viewFrustumChanged=%s || nodeData->nodeBag.isEmpty() =%s)...\n",
|
||||||
debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty()));
|
debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty()));
|
||||||
if (nodeData->getLastTimeBagEmpty() > 0) {
|
if (nodeData->getLastTimeBagEmpty() > 0) {
|
||||||
float elapsedSceneSend = (now - nodeData->getLastTimeBagEmpty()) / 1000000.0f;
|
float elapsedSceneSend = (now - nodeData->getLastTimeBagEmpty()) / 1000000.0f;
|
||||||
if (viewFrustumChanged) {
|
if (viewFrustumChanged) {
|
||||||
printf("viewFrustumChanged resetting after elapsed time to send scene = %f seconds", elapsedSceneSend);
|
qDebug("viewFrustumChanged resetting after elapsed time to send scene = %f seconds", elapsedSceneSend);
|
||||||
} else {
|
} else {
|
||||||
printf("elapsed time to send scene = %f seconds", elapsedSceneSend);
|
qDebug("elapsed time to send scene = %f seconds", elapsedSceneSend);
|
||||||
}
|
}
|
||||||
printf(" [occlusionCulling:%s, wantDelta:%s, wantColor:%s ]\n",
|
qDebug(" [occlusionCulling:%s, wantDelta:%s, wantColor:%s ]\n",
|
||||||
debug::valueOf(nodeData->getWantOcclusionCulling()), debug::valueOf(wantDelta),
|
debug::valueOf(nodeData->getWantOcclusionCulling()), debug::valueOf(wantDelta),
|
||||||
debug::valueOf(wantColor));
|
debug::valueOf(wantColor));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if our view has changed, we need to reset these things...
|
// if our view has changed, we need to reset these things...
|
||||||
if (viewFrustumChanged) {
|
if (viewFrustumChanged) {
|
||||||
if (nodeData->moveShouldDump() || nodeData->hasLodChanged()) {
|
if (nodeData->moveShouldDump() || nodeData->hasLodChanged()) {
|
||||||
nodeData->dumpOutOfView();
|
nodeData->dumpOutOfView();
|
||||||
}
|
}
|
||||||
nodeData->map.erase();
|
nodeData->map.erase();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!viewFrustumChanged && !nodeData->getWantDelta()) {
|
if (!viewFrustumChanged && !nodeData->getWantDelta()) {
|
||||||
// only set our last sent time if we weren't resetting due to frustum change
|
// only set our last sent time if we weren't resetting due to frustum change
|
||||||
uint64_t now = usecTimestampNow();
|
uint64_t now = usecTimestampNow();
|
||||||
|
@ -313,34 +318,42 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
|
||||||
nodeData->stats.sceneCompleted();
|
nodeData->stats.sceneCompleted();
|
||||||
::endSceneSleepTime = _usleepTime;
|
::endSceneSleepTime = _usleepTime;
|
||||||
unsigned long sleepTime = ::endSceneSleepTime - ::startSceneSleepTime;
|
unsigned long sleepTime = ::endSceneSleepTime - ::startSceneSleepTime;
|
||||||
|
|
||||||
unsigned long encodeTime = nodeData->stats.getTotalEncodeTime();
|
unsigned long encodeTime = nodeData->stats.getTotalEncodeTime();
|
||||||
unsigned long elapsedTime = nodeData->stats.getElapsedTime();
|
unsigned long elapsedTime = nodeData->stats.getElapsedTime();
|
||||||
packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
|
|
||||||
|
|
||||||
if (_myServer->wantsDebugSending()) {
|
if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) {
|
||||||
qDebug() << "Scene completed at " << usecTimestampNow()
|
qDebug("about to call handlePacketSend() .... line: %d -- completed scene \n", __LINE__ );
|
||||||
<< "encodeTime:" << encodeTime
|
}
|
||||||
<< " sleepTime:" << sleepTime
|
int packetsJustSent = handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
|
||||||
<< " elapsed:" << elapsedTime
|
packetsSentThisInterval += packetsJustSent;
|
||||||
<< " Packets:" << _totalPackets
|
if (forceDebugging) {
|
||||||
<< " Bytes:" << _totalBytes
|
qDebug("packetsJustSent=%d packetsSentThisInterval=%d\n", packetsJustSent, packetsSentThisInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (forceDebugging || _myServer->wantsDebugSending()) {
|
||||||
|
qDebug() << "Scene completed at " << usecTimestampNow()
|
||||||
|
<< "encodeTime:" << encodeTime
|
||||||
|
<< " sleepTime:" << sleepTime
|
||||||
|
<< " elapsed:" << elapsedTime
|
||||||
|
<< " Packets:" << _totalPackets
|
||||||
|
<< " Bytes:" << _totalBytes
|
||||||
<< " Wasted:" << _totalWastedBytes << "\n";
|
<< " Wasted:" << _totalWastedBytes << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
// start tracking our stats
|
// start tracking our stats
|
||||||
bool isFullScene = ((!viewFrustumChanged || !nodeData->getWantDelta())
|
bool isFullScene = ((!viewFrustumChanged || !nodeData->getWantDelta())
|
||||||
&& nodeData->getViewFrustumJustStoppedChanging()) || nodeData->hasLodChanged();
|
&& nodeData->getViewFrustumJustStoppedChanging()) || nodeData->hasLodChanged();
|
||||||
|
|
||||||
// If we're starting a full scene, then definitely we want to empty the nodeBag
|
// If we're starting a full scene, then definitely we want to empty the nodeBag
|
||||||
if (isFullScene) {
|
if (isFullScene) {
|
||||||
nodeData->nodeBag.deleteAll();
|
nodeData->nodeBag.deleteAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_myServer->wantsDebugSending()) {
|
if (forceDebugging || _myServer->wantsDebugSending()) {
|
||||||
qDebug() << "Scene started at " << usecTimestampNow()
|
qDebug() << "Scene started at " << usecTimestampNow()
|
||||||
<< " Packets:" << _totalPackets
|
<< " Packets:" << _totalPackets
|
||||||
<< " Bytes:" << _totalBytes
|
<< " Bytes:" << _totalBytes
|
||||||
<< " Wasted:" << _totalWastedBytes << "\n";
|
<< " Wasted:" << _totalWastedBytes << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,18 +380,19 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
|
||||||
|
|
||||||
int clientMaxPacketsPerInterval = std::max(1,(nodeData->getMaxOctreePacketsPerSecond() / INTERVALS_PER_SECOND));
|
int clientMaxPacketsPerInterval = std::max(1,(nodeData->getMaxOctreePacketsPerSecond() / INTERVALS_PER_SECOND));
|
||||||
int maxPacketsPerInterval = std::min(clientMaxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval());
|
int maxPacketsPerInterval = std::min(clientMaxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval());
|
||||||
|
|
||||||
if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
|
if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
|
||||||
printf("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n",
|
qDebug("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n",
|
||||||
truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(),
|
truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(),
|
||||||
nodeData->getMaxOctreePacketsPerSecond(), clientMaxPacketsPerInterval);
|
nodeData->getMaxOctreePacketsPerSecond(), clientMaxPacketsPerInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
int extraPackingAttempts = 0;
|
int extraPackingAttempts = 0;
|
||||||
|
bool completedScene = false;
|
||||||
while (somethingToSend && packetsSentThisInterval < maxPacketsPerInterval) {
|
while (somethingToSend && packetsSentThisInterval < maxPacketsPerInterval) {
|
||||||
if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
|
if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
|
||||||
printf("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n",
|
qDebug("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n",
|
||||||
truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(),
|
truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(),
|
||||||
nodeData->getMaxOctreePacketsPerSecond(), clientMaxPacketsPerInterval);
|
nodeData->getMaxOctreePacketsPerSecond(), clientMaxPacketsPerInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,27 +405,32 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
|
||||||
float voxelSizeScale = nodeData->getOctreeSizeScale();
|
float voxelSizeScale = nodeData->getOctreeSizeScale();
|
||||||
int boundaryLevelAdjustClient = nodeData->getBoundaryLevelAdjust();
|
int boundaryLevelAdjustClient = nodeData->getBoundaryLevelAdjust();
|
||||||
|
|
||||||
int boundaryLevelAdjust = boundaryLevelAdjustClient + (viewFrustumChanged && nodeData->getWantLowResMoving()
|
int boundaryLevelAdjust = boundaryLevelAdjustClient + (viewFrustumChanged && nodeData->getWantLowResMoving()
|
||||||
? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST);
|
? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST);
|
||||||
|
|
||||||
|
|
||||||
bool isFullScene = ((!viewFrustumChanged || !nodeData->getWantDelta()) &&
|
bool isFullScene = ((!viewFrustumChanged || !nodeData->getWantDelta()) &&
|
||||||
nodeData->getViewFrustumJustStoppedChanging()) || nodeData->hasLodChanged();
|
nodeData->getViewFrustumJustStoppedChanging()) || nodeData->hasLodChanged();
|
||||||
|
|
||||||
EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor,
|
EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor,
|
||||||
WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum,
|
WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum,
|
||||||
wantOcclusionCulling, coverageMap, boundaryLevelAdjust, voxelSizeScale,
|
wantOcclusionCulling, coverageMap, boundaryLevelAdjust, voxelSizeScale,
|
||||||
nodeData->getLastTimeBagEmpty(),
|
nodeData->getLastTimeBagEmpty(),
|
||||||
isFullScene, &nodeData->stats, _myServer->getJurisdiction());
|
isFullScene, &nodeData->stats, _myServer->getJurisdiction());
|
||||||
|
|
||||||
|
|
||||||
_myServer->getOctree()->lockForRead();
|
_myServer->getOctree()->lockForRead();
|
||||||
nodeData->stats.encodeStarted();
|
nodeData->stats.encodeStarted();
|
||||||
bytesWritten = _myServer->getOctree()->encodeTreeBitstream(subTree, &_packetData, nodeData->nodeBag, params);
|
bytesWritten = _myServer->getOctree()->encodeTreeBitstream(subTree, &_packetData, nodeData->nodeBag, params);
|
||||||
|
|
||||||
|
// If after calling encodeTreeBitstream() there are no nodes left to send, then we know we've
|
||||||
|
// sent the entire scene. We want to know this below so we'll actually write this content into
|
||||||
|
// the packet and send it
|
||||||
|
completedScene = nodeData->nodeBag.isEmpty();
|
||||||
|
|
||||||
// if we're trying to fill a full size packet, then we use this logic to determine if we have a DIDNT_FIT case.
|
// if we're trying to fill a full size packet, then we use this logic to determine if we have a DIDNT_FIT case.
|
||||||
if (_packetData.getTargetSize() == MAX_OCTREE_PACKET_DATA_SIZE) {
|
if (_packetData.getTargetSize() == MAX_OCTREE_PACKET_DATA_SIZE) {
|
||||||
if (_packetData.hasContent() && bytesWritten == 0 &&
|
if (_packetData.hasContent() && bytesWritten == 0 &&
|
||||||
params.stopReason == EncodeBitstreamParams::DIDNT_FIT) {
|
params.stopReason == EncodeBitstreamParams::DIDNT_FIT) {
|
||||||
lastNodeDidntFit = true;
|
lastNodeDidntFit = true;
|
||||||
}
|
}
|
||||||
|
@ -432,51 +451,56 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
|
||||||
bytesWritten = 0;
|
bytesWritten = 0;
|
||||||
somethingToSend = false; // this will cause us to drop out of the loop...
|
somethingToSend = false; // this will cause us to drop out of the loop...
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the last node didn't fit, but we're in compressed mode, then we actually want to see if we can fit a
|
// If the last node didn't fit, but we're in compressed mode, then we actually want to see if we can fit a
|
||||||
// little bit more in this packet. To do this we
|
// little bit more in this packet. To do this we write into the packet, but don't send it yet, we'll
|
||||||
|
// keep attempting to write in compressed mode to add more compressed segments
|
||||||
|
|
||||||
// We only consider sending anything if there is something in the _packetData to send... But
|
// We only consider sending anything if there is something in the _packetData to send... But
|
||||||
// if bytesWritten == 0 it means either the subTree couldn't fit or we had an empty bag... Both cases
|
// if bytesWritten == 0 it means either the subTree couldn't fit or we had an empty bag... Both cases
|
||||||
// mean we should send the previous packet contents and reset it.
|
// mean we should send the previous packet contents and reset it.
|
||||||
if (lastNodeDidntFit) {
|
if (completedScene || lastNodeDidntFit) {
|
||||||
if (_packetData.hasContent()) {
|
if (_packetData.hasContent()) {
|
||||||
// if for some reason the finalized size is greater than our available size, then probably the "compressed"
|
// if for some reason the finalized size is greater than our available size, then probably the "compressed"
|
||||||
// form actually inflated beyond our padding, and in this case we will send the current packet, then
|
// form actually inflated beyond our padding, and in this case we will send the current packet, then
|
||||||
// write to out new packet...
|
// write to out new packet...
|
||||||
int writtenSize = _packetData.getFinalizedSize()
|
int writtenSize = _packetData.getFinalizedSize()
|
||||||
+ (nodeData->getCurrentPacketIsCompressed() ? sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE) : 0);
|
+ (nodeData->getCurrentPacketIsCompressed() ? sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE) : 0);
|
||||||
|
|
||||||
|
|
||||||
if (writtenSize > nodeData->getAvailable()) {
|
if (writtenSize > nodeData->getAvailable()) {
|
||||||
if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
|
if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) {
|
||||||
printf("writtenSize[%d] > available[%d] too big, sending packet as is.\n",
|
qDebug("about to call handlePacketSend() .... line: %d -- "
|
||||||
writtenSize, nodeData->getAvailable());
|
"writtenSize[%d] > available[%d] too big, sending packet as is.\n",
|
||||||
|
__LINE__, writtenSize, nodeData->getAvailable());
|
||||||
}
|
}
|
||||||
packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
|
packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
|
if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) {
|
||||||
printf("calling writeToPacket() available=%d compressedSize=%d uncompressedSize=%d target=%d\n",
|
qDebug(">>>>>> calling writeToPacket() available=%d compressedSize=%d uncompressedSize=%d target=%d\n",
|
||||||
nodeData->getAvailable(), _packetData.getFinalizedSize(),
|
nodeData->getAvailable(), _packetData.getFinalizedSize(),
|
||||||
_packetData.getUncompressedSize(), _packetData.getTargetSize());
|
_packetData.getUncompressedSize(), _packetData.getTargetSize());
|
||||||
}
|
}
|
||||||
nodeData->writeToPacket(_packetData.getFinalizedData(), _packetData.getFinalizedSize());
|
nodeData->writeToPacket(_packetData.getFinalizedData(), _packetData.getFinalizedSize());
|
||||||
extraPackingAttempts = 0;
|
extraPackingAttempts = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're not running compressed, the we know we can just send now. Or if we're running compressed, but
|
// If we're not running compressed, then we know we can just send now. Or if we're running compressed, but
|
||||||
// the packet doesn't have enough space to bother attempting to pack more...
|
// the packet doesn't have enough space to bother attempting to pack more...
|
||||||
bool sendNow = true;
|
bool sendNow = true;
|
||||||
|
|
||||||
if (nodeData->getCurrentPacketIsCompressed() &&
|
if (nodeData->getCurrentPacketIsCompressed() &&
|
||||||
nodeData->getAvailable() >= MINIMUM_ATTEMPT_MORE_PACKING &&
|
nodeData->getAvailable() >= MINIMUM_ATTEMPT_MORE_PACKING &&
|
||||||
extraPackingAttempts <= REASONABLE_NUMBER_OF_PACKING_ATTEMPTS) {
|
extraPackingAttempts <= REASONABLE_NUMBER_OF_PACKING_ATTEMPTS) {
|
||||||
sendNow = false; // try to pack more
|
sendNow = false; // try to pack more
|
||||||
}
|
}
|
||||||
|
|
||||||
int targetSize = MAX_OCTREE_PACKET_DATA_SIZE;
|
int targetSize = MAX_OCTREE_PACKET_DATA_SIZE;
|
||||||
if (sendNow) {
|
if (sendNow) {
|
||||||
|
if (forceDebugging) {
|
||||||
|
qDebug("about to call handlePacketSend() .... line: %d -- sendNow = TRUE\n", __LINE__);
|
||||||
|
}
|
||||||
packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
|
packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
|
||||||
if (wantCompression) {
|
if (wantCompression) {
|
||||||
targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE);
|
targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE);
|
||||||
|
@ -491,14 +515,14 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
|
||||||
targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE) - COMPRESS_PADDING;
|
targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE) - COMPRESS_PADDING;
|
||||||
}
|
}
|
||||||
if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
|
if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
|
||||||
printf("line:%d _packetData.changeSettings() wantCompression=%s targetSize=%d\n",__LINE__,
|
qDebug("line:%d _packetData.changeSettings() wantCompression=%s targetSize=%d\n",__LINE__,
|
||||||
debug::valueOf(nodeData->getWantCompression()), targetSize);
|
debug::valueOf(nodeData->getWantCompression()), targetSize);
|
||||||
}
|
}
|
||||||
_packetData.changeSettings(nodeData->getWantCompression(), targetSize); // will do reset
|
_packetData.changeSettings(nodeData->getWantCompression(), targetSize); // will do reset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Here's where we can/should allow the server to send other data...
|
// Here's where we can/should allow the server to send other data...
|
||||||
// send the environment packet
|
// send the environment packet
|
||||||
if (_myServer->hasSpecialPacketToSend()) {
|
if (_myServer->hasSpecialPacketToSend()) {
|
||||||
|
@ -506,14 +530,14 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
|
||||||
truePacketsSent++;
|
truePacketsSent++;
|
||||||
packetsSentThisInterval++;
|
packetsSentThisInterval++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint64_t end = usecTimestampNow();
|
uint64_t end = usecTimestampNow();
|
||||||
int elapsedmsec = (end - start)/1000;
|
int elapsedmsec = (end - start)/1000;
|
||||||
|
|
||||||
uint64_t endCompressCalls = OctreePacketData::getCompressContentCalls();
|
uint64_t endCompressCalls = OctreePacketData::getCompressContentCalls();
|
||||||
int elapsedCompressCalls = endCompressCalls - startCompressCalls;
|
int elapsedCompressCalls = endCompressCalls - startCompressCalls;
|
||||||
|
|
||||||
uint64_t endCompressTimeMsecs = OctreePacketData::getCompressContentTime() / 1000;
|
uint64_t endCompressTimeMsecs = OctreePacketData::getCompressContentTime() / 1000;
|
||||||
int elapsedCompressTimeMsecs = endCompressTimeMsecs - startCompressTimeMsecs;
|
int elapsedCompressTimeMsecs = endCompressTimeMsecs - startCompressTimeMsecs;
|
||||||
|
|
||||||
|
@ -521,18 +545,24 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
|
||||||
if (elapsedmsec > 100) {
|
if (elapsedmsec > 100) {
|
||||||
if (elapsedmsec > 1000) {
|
if (elapsedmsec > 1000) {
|
||||||
int elapsedsec = (end - start)/1000000;
|
int elapsedsec = (end - start)/1000000;
|
||||||
printf("WARNING! packetLoop() took %d seconds [%d milliseconds %d calls in compress] to generate %d bytes in %d packets %d nodes still to send\n",
|
qDebug("WARNING! packetLoop() took %d seconds [%d milliseconds %d calls in compress] "
|
||||||
elapsedsec, elapsedCompressTimeMsecs, elapsedCompressCalls, trueBytesSent, truePacketsSent, nodeData->nodeBag.count());
|
"to generate %d bytes in %d packets %d nodes still to send\n",
|
||||||
|
elapsedsec, elapsedCompressTimeMsecs, elapsedCompressCalls,
|
||||||
|
trueBytesSent, truePacketsSent, nodeData->nodeBag.count());
|
||||||
} else {
|
} else {
|
||||||
printf("WARNING! packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] to generate %d bytes in %d packets, %d nodes still to send\n",
|
qDebug("WARNING! packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] "
|
||||||
elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls, trueBytesSent, truePacketsSent, nodeData->nodeBag.count());
|
"to generate %d bytes in %d packets, %d nodes still to send\n",
|
||||||
|
elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls,
|
||||||
|
trueBytesSent, truePacketsSent, nodeData->nodeBag.count());
|
||||||
}
|
}
|
||||||
} else if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
|
} else if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
|
||||||
printf("packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] to generate %d bytes in %d packets, %d nodes still to send\n",
|
qDebug("packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] "
|
||||||
elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls, trueBytesSent, truePacketsSent, nodeData->nodeBag.count());
|
"to generate %d bytes in %d packets, %d nodes still to send\n",
|
||||||
|
elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls,
|
||||||
|
trueBytesSent, truePacketsSent, nodeData->nodeBag.count());
|
||||||
}
|
}
|
||||||
|
|
||||||
// if after sending packets we've emptied our bag, then we want to remember that we've sent all
|
// if after sending packets we've emptied our bag, then we want to remember that we've sent all
|
||||||
// the voxels from the current view frustum
|
// the voxels from the current view frustum
|
||||||
if (nodeData->nodeBag.isEmpty()) {
|
if (nodeData->nodeBag.isEmpty()) {
|
||||||
nodeData->updateLastKnownViewFrustum();
|
nodeData->updateLastKnownViewFrustum();
|
||||||
|
@ -544,11 +574,13 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
|
if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
|
||||||
printf("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n",
|
qDebug("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d "
|
||||||
truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(),
|
"server PPI=%d nodePPS=%d nodePPI=%d\n",
|
||||||
nodeData->getMaxOctreePacketsPerSecond(), clientMaxPacketsPerInterval);
|
truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval,
|
||||||
|
_myServer->getPacketsPerClientPerInterval(), nodeData->getMaxOctreePacketsPerSecond(),
|
||||||
|
clientMaxPacketsPerInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end if bag wasn't empty, and so we sent stuff...
|
} // end if bag wasn't empty, and so we sent stuff...
|
||||||
|
|
||||||
return truePacketsSent;
|
return truePacketsSent;
|
||||||
|
|
|
@ -514,7 +514,7 @@ void OctreeServer::processDatagram(const QByteArray& dataByteArray, const HifiSo
|
||||||
if (packetType == getMyQueryMessageType()) {
|
if (packetType == getMyQueryMessageType()) {
|
||||||
bool debug = false;
|
bool debug = false;
|
||||||
if (debug) {
|
if (debug) {
|
||||||
qDebug() << "Got PACKET_TYPE_VOXEL_QUERY at " << usecTimestampNow() << "\n";
|
qDebug() << "Got PACKET_TYPE_VOXEL_QUERY at" << usecTimestampNow() << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
int numBytesPacketHeader = numBytesForPacketHeader((unsigned char*) dataByteArray.data());
|
int numBytesPacketHeader = numBytesForPacketHeader((unsigned char*) dataByteArray.data());
|
||||||
|
|
|
@ -54,7 +54,7 @@ void OctreeElement::init(unsigned char * octalCode) {
|
||||||
memcpy(_octalCode.buffer, octalCode, octalCodeLength);
|
memcpy(_octalCode.buffer, octalCode, octalCodeLength);
|
||||||
delete[] octalCode;
|
delete[] octalCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set up the _children union
|
// set up the _children union
|
||||||
_childBitmask = 0;
|
_childBitmask = 0;
|
||||||
_childrenExternal = false;
|
_childrenExternal = false;
|
||||||
|
@ -64,7 +64,7 @@ void OctreeElement::init(unsigned char * octalCode) {
|
||||||
_singleChildrenCount++;
|
_singleChildrenCount++;
|
||||||
#endif
|
#endif
|
||||||
_childrenCount[0]++;
|
_childrenCount[0]++;
|
||||||
|
|
||||||
// default pointers to child nodes to NULL
|
// default pointers to child nodes to NULL
|
||||||
#ifdef HAS_AUDIT_CHILDREN
|
#ifdef HAS_AUDIT_CHILDREN
|
||||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||||
|
@ -81,7 +81,7 @@ void OctreeElement::init(unsigned char * octalCode) {
|
||||||
#ifdef SIMPLE_EXTERNAL_CHILDREN
|
#ifdef SIMPLE_EXTERNAL_CHILDREN
|
||||||
_children.single = NULL;
|
_children.single = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_isDirty = true;
|
_isDirty = true;
|
||||||
_shouldRender = false;
|
_shouldRender = false;
|
||||||
_sourceUUIDKey = 0;
|
_sourceUUIDKey = 0;
|
||||||
|
@ -100,13 +100,13 @@ OctreeElement::~OctreeElement() {
|
||||||
_octcodeMemoryUsage -= bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(getOctalCode()));
|
_octcodeMemoryUsage -= bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(getOctalCode()));
|
||||||
delete[] _octalCode.pointer;
|
delete[] _octalCode.pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete all of this node's children, this also takes care of all population tracking data
|
// delete all of this node's children, this also takes care of all population tracking data
|
||||||
deleteAllChildren();
|
deleteAllChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OctreeElement::markWithChangedTime() {
|
void OctreeElement::markWithChangedTime() {
|
||||||
_lastChanged = usecTimestampNow();
|
_lastChanged = usecTimestampNow();
|
||||||
notifyUpdateHooks(); // if the node has changed, notify our hooks
|
notifyUpdateHooks(); // if the node has changed, notify our hooks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ void OctreeElement::handleSubtreeChanged(Octree* myTree) {
|
||||||
if (myTree->getShouldReaverage()) {
|
if (myTree->getShouldReaverage()) {
|
||||||
calculateAverageFromChildren();
|
calculateAverageFromChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
markWithChangedTime();
|
markWithChangedTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,10 +184,10 @@ void OctreeElement::setShouldRender(bool shouldRender) {
|
||||||
|
|
||||||
void OctreeElement::calculateAABox() {
|
void OctreeElement::calculateAABox() {
|
||||||
glm::vec3 corner;
|
glm::vec3 corner;
|
||||||
|
|
||||||
// copy corner into box
|
// copy corner into box
|
||||||
copyFirstVertexForCode(getOctalCode(),(float*)&corner);
|
copyFirstVertexForCode(getOctalCode(),(float*)&corner);
|
||||||
|
|
||||||
// this tells you the "size" of the voxel
|
// this tells you the "size" of the voxel
|
||||||
float voxelScale = 1 / powf(2, numberOfThreeBitSectionsInCode(getOctalCode()));
|
float voxelScale = 1 / powf(2, numberOfThreeBitSectionsInCode(getOctalCode()));
|
||||||
_box.setBox(corner,voxelScale);
|
_box.setBox(corner,voxelScale);
|
||||||
|
@ -201,7 +201,7 @@ void OctreeElement::deleteChildAtIndex(int childIndex) {
|
||||||
setChildAtIndex(childIndex, NULL);
|
setChildAtIndex(childIndex, NULL);
|
||||||
_isDirty = true;
|
_isDirty = true;
|
||||||
markWithChangedTime();
|
markWithChangedTime();
|
||||||
|
|
||||||
// after deleting the child, check to see if we're a leaf
|
// after deleting the child, check to see if we're a leaf
|
||||||
if (isLeaf()) {
|
if (isLeaf()) {
|
||||||
_voxelNodeLeafCount++;
|
_voxelNodeLeafCount++;
|
||||||
|
@ -219,13 +219,13 @@ OctreeElement* OctreeElement::removeChildAtIndex(int childIndex) {
|
||||||
setChildAtIndex(childIndex, NULL);
|
setChildAtIndex(childIndex, NULL);
|
||||||
_isDirty = true;
|
_isDirty = true;
|
||||||
markWithChangedTime();
|
markWithChangedTime();
|
||||||
|
|
||||||
// after removing the child, check to see if we're a leaf
|
// after removing the child, check to see if we're a leaf
|
||||||
if (isLeaf()) {
|
if (isLeaf()) {
|
||||||
_voxelNodeLeafCount++;
|
_voxelNodeLeafCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAS_AUDIT_CHILDREN
|
#ifdef HAS_AUDIT_CHILDREN
|
||||||
auditChildren("removeChildAtIndex()");
|
auditChildren("removeChildAtIndex()");
|
||||||
#endif // def HAS_AUDIT_CHILDREN
|
#endif // def HAS_AUDIT_CHILDREN
|
||||||
|
@ -238,12 +238,12 @@ void OctreeElement::auditChildren(const char* label) const {
|
||||||
for (int childIndex = 0; childIndex < NUMBER_OF_CHILDREN; childIndex++) {
|
for (int childIndex = 0; childIndex < NUMBER_OF_CHILDREN; childIndex++) {
|
||||||
OctreeElement* testChildNew = getChildAtIndex(childIndex);
|
OctreeElement* testChildNew = getChildAtIndex(childIndex);
|
||||||
OctreeElement* testChildOld = _childrenArray[childIndex];
|
OctreeElement* testChildOld = _childrenArray[childIndex];
|
||||||
|
|
||||||
if (testChildNew != testChildOld) {
|
if (testChildNew != testChildOld) {
|
||||||
auditFailed = true;
|
auditFailed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool alwaysReport = false; // set this to true to get additional debugging
|
const bool alwaysReport = false; // set this to true to get additional debugging
|
||||||
if (alwaysReport || auditFailed) {
|
if (alwaysReport || auditFailed) {
|
||||||
qDebug("%s... auditChildren() %s <<<< \n", label, (auditFailed ? "FAILED" : "PASSED"));
|
qDebug("%s... auditChildren() %s <<<< \n", label, (auditFailed ? "FAILED" : "PASSED"));
|
||||||
|
@ -309,7 +309,7 @@ OctreeElement* OctreeElement::getChildAtIndex(int childIndex) const {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default : {
|
default : {
|
||||||
return _children.external[childIndex];
|
return _children.external[childIndex];
|
||||||
} break;
|
} break;
|
||||||
|
@ -320,11 +320,11 @@ OctreeElement* OctreeElement::getChildAtIndex(int childIndex) const {
|
||||||
PerformanceWarning warn(false,"getChildAtIndex",false,&_getChildAtIndexTime,&_getChildAtIndexCalls);
|
PerformanceWarning warn(false,"getChildAtIndex",false,&_getChildAtIndexTime,&_getChildAtIndexCalls);
|
||||||
OctreeElement* result = NULL;
|
OctreeElement* result = NULL;
|
||||||
int childCount = getChildCount();
|
int childCount = getChildCount();
|
||||||
|
|
||||||
#ifdef HAS_AUDIT_CHILDREN
|
#ifdef HAS_AUDIT_CHILDREN
|
||||||
const char* caseStr = NULL;
|
const char* caseStr = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch (childCount) {
|
switch (childCount) {
|
||||||
case 0:
|
case 0:
|
||||||
#ifdef HAS_AUDIT_CHILDREN
|
#ifdef HAS_AUDIT_CHILDREN
|
||||||
|
@ -424,7 +424,7 @@ OctreeElement* OctreeElement::getChildAtIndex(int childIndex) const {
|
||||||
caseStr, result,_childrenArray[childIndex]);
|
caseStr, result,_childrenArray[childIndex]);
|
||||||
}
|
}
|
||||||
#endif // def HAS_AUDIT_CHILDREN
|
#endif // def HAS_AUDIT_CHILDREN
|
||||||
return result;
|
return result;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -435,7 +435,7 @@ void OctreeElement::storeTwoChildren(OctreeElement* childOne, OctreeElement* chi
|
||||||
|
|
||||||
const int64_t minOffset = std::numeric_limits<int32_t>::min();
|
const int64_t minOffset = std::numeric_limits<int32_t>::min();
|
||||||
const int64_t maxOffset = std::numeric_limits<int32_t>::max();
|
const int64_t maxOffset = std::numeric_limits<int32_t>::max();
|
||||||
|
|
||||||
bool forceExternal = true;
|
bool forceExternal = true;
|
||||||
if (!forceExternal && isBetween(offsetOne, maxOffset, minOffset) && isBetween(offsetTwo, maxOffset, minOffset)) {
|
if (!forceExternal && isBetween(offsetOne, maxOffset, minOffset) && isBetween(offsetTwo, maxOffset, minOffset)) {
|
||||||
// if previously external, then clean it up...
|
// if previously external, then clean it up...
|
||||||
|
@ -455,7 +455,7 @@ void OctreeElement::storeTwoChildren(OctreeElement* childOne, OctreeElement* chi
|
||||||
_twoChildrenOffsetCount++;
|
_twoChildrenOffsetCount++;
|
||||||
} else {
|
} else {
|
||||||
// encode in array
|
// encode in array
|
||||||
|
|
||||||
// if not previously external, then allocate appropriately
|
// if not previously external, then allocate appropriately
|
||||||
if (!_childrenExternal) {
|
if (!_childrenExternal) {
|
||||||
_childrenExternal = true;
|
_childrenExternal = true;
|
||||||
|
@ -516,7 +516,7 @@ void OctreeElement::encodeThreeOffsets(int64_t offsetOne, int64_t offsetTwo, int
|
||||||
const uint64_t ENCODE_BITS = 21;
|
const uint64_t ENCODE_BITS = 21;
|
||||||
const uint64_t ENCODE_MASK = 0xFFFFF;
|
const uint64_t ENCODE_MASK = 0xFFFFF;
|
||||||
const uint64_t ENCODE_MASK_SIGN = 0x100000;
|
const uint64_t ENCODE_MASK_SIGN = 0x100000;
|
||||||
|
|
||||||
uint64_t offsetEncodedOne, offsetEncodedTwo, offsetEncodedThree;
|
uint64_t offsetEncodedOne, offsetEncodedTwo, offsetEncodedThree;
|
||||||
if (offsetOne < 0) {
|
if (offsetOne < 0) {
|
||||||
offsetEncodedOne = ((-offsetOne & ENCODE_MASK) | ENCODE_MASK_SIGN);
|
offsetEncodedOne = ((-offsetOne & ENCODE_MASK) | ENCODE_MASK_SIGN);
|
||||||
|
@ -544,13 +544,13 @@ void OctreeElement::storeThreeChildren(OctreeElement* childOne, OctreeElement* c
|
||||||
int64_t offsetOne = (uint8_t*)childOne - (uint8_t*)this;
|
int64_t offsetOne = (uint8_t*)childOne - (uint8_t*)this;
|
||||||
int64_t offsetTwo = (uint8_t*)childTwo - (uint8_t*)this;
|
int64_t offsetTwo = (uint8_t*)childTwo - (uint8_t*)this;
|
||||||
int64_t offsetThree = (uint8_t*)childThree - (uint8_t*)this;
|
int64_t offsetThree = (uint8_t*)childThree - (uint8_t*)this;
|
||||||
|
|
||||||
const int64_t minOffset = -1048576; // what can fit in 20 bits // std::numeric_limits<int16_t>::min();
|
const int64_t minOffset = -1048576; // what can fit in 20 bits // std::numeric_limits<int16_t>::min();
|
||||||
const int64_t maxOffset = 1048576; // what can fit in 20 bits // std::numeric_limits<int16_t>::max();
|
const int64_t maxOffset = 1048576; // what can fit in 20 bits // std::numeric_limits<int16_t>::max();
|
||||||
|
|
||||||
bool forceExternal = true;
|
bool forceExternal = true;
|
||||||
if (!forceExternal &&
|
if (!forceExternal &&
|
||||||
isBetween(offsetOne, maxOffset, minOffset) &&
|
isBetween(offsetOne, maxOffset, minOffset) &&
|
||||||
isBetween(offsetTwo, maxOffset, minOffset) &&
|
isBetween(offsetTwo, maxOffset, minOffset) &&
|
||||||
isBetween(offsetThree, maxOffset, minOffset)) {
|
isBetween(offsetThree, maxOffset, minOffset)) {
|
||||||
// if previously external, then clean it up...
|
// if previously external, then clean it up...
|
||||||
|
@ -566,7 +566,7 @@ void OctreeElement::storeThreeChildren(OctreeElement* childOne, OctreeElement* c
|
||||||
_threeChildrenOffsetCount++;
|
_threeChildrenOffsetCount++;
|
||||||
} else {
|
} else {
|
||||||
// encode in array
|
// encode in array
|
||||||
|
|
||||||
// if not previously external, then allocate appropriately
|
// if not previously external, then allocate appropriately
|
||||||
if (!_childrenExternal) {
|
if (!_childrenExternal) {
|
||||||
_childrenExternal = true;
|
_childrenExternal = true;
|
||||||
|
@ -609,13 +609,13 @@ void OctreeElement::checkStoreFourChildren(OctreeElement* childOne, OctreeElemen
|
||||||
int64_t offsetTwo = (uint8_t*)childTwo - (uint8_t*)this;
|
int64_t offsetTwo = (uint8_t*)childTwo - (uint8_t*)this;
|
||||||
int64_t offsetThree = (uint8_t*)childThree - (uint8_t*)this;
|
int64_t offsetThree = (uint8_t*)childThree - (uint8_t*)this;
|
||||||
int64_t offsetFour = (uint8_t*)childFour - (uint8_t*)this;
|
int64_t offsetFour = (uint8_t*)childFour - (uint8_t*)this;
|
||||||
|
|
||||||
const int64_t minOffset = std::numeric_limits<int16_t>::min();
|
const int64_t minOffset = std::numeric_limits<int16_t>::min();
|
||||||
const int64_t maxOffset = std::numeric_limits<int16_t>::max();
|
const int64_t maxOffset = std::numeric_limits<int16_t>::max();
|
||||||
|
|
||||||
bool forceExternal = true;
|
bool forceExternal = true;
|
||||||
if (!forceExternal &&
|
if (!forceExternal &&
|
||||||
isBetween(offsetOne, maxOffset, minOffset) &&
|
isBetween(offsetOne, maxOffset, minOffset) &&
|
||||||
isBetween(offsetTwo, maxOffset, minOffset) &&
|
isBetween(offsetTwo, maxOffset, minOffset) &&
|
||||||
isBetween(offsetThree, maxOffset, minOffset) &&
|
isBetween(offsetThree, maxOffset, minOffset) &&
|
||||||
isBetween(offsetFour, maxOffset, minOffset)
|
isBetween(offsetFour, maxOffset, minOffset)
|
||||||
|
@ -671,10 +671,10 @@ void OctreeElement::deleteAllChildren() {
|
||||||
_externalChildrenCount--;
|
_externalChildrenCount--;
|
||||||
_childrenCount[childCount]--;
|
_childrenCount[childCount]--;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we had externally stored children, clean them too.
|
// If we had externally stored children, clean them too.
|
||||||
if (_childrenExternal && _children.external) {
|
if (_childrenExternal && _children.external) {
|
||||||
delete[] _children.external;
|
delete[] _children.external;
|
||||||
|
@ -734,7 +734,7 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
|
||||||
_children.external[childIndex] = child;
|
_children.external[childIndex] = child;
|
||||||
|
|
||||||
_externalChildrenMemoryUsage += NUMBER_OF_CHILDREN * sizeof(OctreeElement*);
|
_externalChildrenMemoryUsage += NUMBER_OF_CHILDREN * sizeof(OctreeElement*);
|
||||||
|
|
||||||
} else if (previousChildCount == 2 && newChildCount == 1) {
|
} else if (previousChildCount == 2 && newChildCount == 1) {
|
||||||
assert(child == NULL); // we are removing a child, so this must be true!
|
assert(child == NULL); // we are removing a child, so this must be true!
|
||||||
OctreeElement* previousFirstChild = _children.external[firstIndex];
|
OctreeElement* previousFirstChild = _children.external[firstIndex];
|
||||||
|
@ -757,7 +757,7 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
|
||||||
|
|
||||||
// Here's how we store things...
|
// Here's how we store things...
|
||||||
// If we have 0 or 1 children, then we just store them in the _children.single;
|
// If we have 0 or 1 children, then we just store them in the _children.single;
|
||||||
// If we have 2 children,
|
// If we have 2 children,
|
||||||
// then if we can we store them as 32 bit signed offsets from our own this pointer,
|
// then if we can we store them as 32 bit signed offsets from our own this pointer,
|
||||||
// _children.offsetsTwoChildren[0]-[1]
|
// _children.offsetsTwoChildren[0]-[1]
|
||||||
// these are 32 bit offsets
|
// these are 32 bit offsets
|
||||||
|
@ -770,7 +770,7 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
|
||||||
clearAtBit(_childBitmask, childIndex);
|
clearAtBit(_childBitmask, childIndex);
|
||||||
}
|
}
|
||||||
int newChildCount = getChildCount();
|
int newChildCount = getChildCount();
|
||||||
|
|
||||||
// track our population data
|
// track our population data
|
||||||
if (previousChildCount != newChildCount) {
|
if (previousChildCount != newChildCount) {
|
||||||
_childrenCount[previousChildCount]--;
|
_childrenCount[previousChildCount]--;
|
||||||
|
@ -781,7 +781,7 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
|
||||||
if (previousChildCount == 0 && newChildCount == 0) {
|
if (previousChildCount == 0 && newChildCount == 0) {
|
||||||
// nothing to do...
|
// nothing to do...
|
||||||
} else if ((previousChildCount == 0 || previousChildCount == 1) && newChildCount == 1) {
|
} else if ((previousChildCount == 0 || previousChildCount == 1) && newChildCount == 1) {
|
||||||
// If we had 0 children, and we're setting our first child or if we had 1 child, or we're resetting the same child,
|
// If we had 0 children, and we're setting our first child or if we had 1 child, or we're resetting the same child,
|
||||||
// then we can just store it in _children.single
|
// then we can just store it in _children.single
|
||||||
_children.single = child;
|
_children.single = child;
|
||||||
} else if (previousChildCount == 1 && newChildCount == 0) {
|
} else if (previousChildCount == 1 && newChildCount == 0) {
|
||||||
|
@ -803,21 +803,21 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
|
||||||
}
|
}
|
||||||
|
|
||||||
_singleChildrenCount--;
|
_singleChildrenCount--;
|
||||||
storeTwoChildren(childOne, childTwo);
|
storeTwoChildren(childOne, childTwo);
|
||||||
} else if (previousChildCount == 2 && newChildCount == 1) {
|
} else if (previousChildCount == 2 && newChildCount == 1) {
|
||||||
// If we had 2 children, and we're removing one, then we know we can go down to single mode
|
// If we had 2 children, and we're removing one, then we know we can go down to single mode
|
||||||
//assert(child == NULL); // this is the only logical case
|
//assert(child == NULL); // this is the only logical case
|
||||||
|
|
||||||
int indexTwo = getNthBit(previousChildMask, 2);
|
int indexTwo = getNthBit(previousChildMask, 2);
|
||||||
bool keepChildOne = indexTwo == childIndex;
|
bool keepChildOne = indexTwo == childIndex;
|
||||||
|
|
||||||
OctreeElement* childOne;
|
OctreeElement* childOne;
|
||||||
OctreeElement* childTwo;
|
OctreeElement* childTwo;
|
||||||
|
|
||||||
retrieveTwoChildren(childOne, childTwo);
|
retrieveTwoChildren(childOne, childTwo);
|
||||||
|
|
||||||
_singleChildrenCount++;
|
_singleChildrenCount++;
|
||||||
|
|
||||||
if (keepChildOne) {
|
if (keepChildOne) {
|
||||||
_children.single = childOne;
|
_children.single = childOne;
|
||||||
} else {
|
} else {
|
||||||
|
@ -825,14 +825,14 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
|
||||||
}
|
}
|
||||||
} else if (previousChildCount == 2 && newChildCount == 2) {
|
} else if (previousChildCount == 2 && newChildCount == 2) {
|
||||||
// If we had 2 children, and still have 2, then we know we are resetting one of our existing children
|
// If we had 2 children, and still have 2, then we know we are resetting one of our existing children
|
||||||
|
|
||||||
int indexOne = getNthBit(previousChildMask, 1);
|
int indexOne = getNthBit(previousChildMask, 1);
|
||||||
bool replaceChildOne = indexOne == childIndex;
|
bool replaceChildOne = indexOne == childIndex;
|
||||||
|
|
||||||
// Get the existing two children out of their encoding...
|
// Get the existing two children out of their encoding...
|
||||||
OctreeElement* childOne;
|
OctreeElement* childOne;
|
||||||
OctreeElement* childTwo;
|
OctreeElement* childTwo;
|
||||||
retrieveTwoChildren(childOne, childTwo);
|
retrieveTwoChildren(childOne, childTwo);
|
||||||
|
|
||||||
if (replaceChildOne) {
|
if (replaceChildOne) {
|
||||||
childOne = child;
|
childOne = child;
|
||||||
|
@ -841,7 +841,7 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
|
||||||
}
|
}
|
||||||
|
|
||||||
storeTwoChildren(childOne, childTwo);
|
storeTwoChildren(childOne, childTwo);
|
||||||
|
|
||||||
} else if (previousChildCount == 2 && newChildCount == 3) {
|
} else if (previousChildCount == 2 && newChildCount == 3) {
|
||||||
// If we had 2 children, and now have 3, then we know we are going to an external case...
|
// If we had 2 children, and now have 3, then we know we are going to an external case...
|
||||||
|
|
||||||
|
@ -850,8 +850,8 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
|
||||||
OctreeElement* childTwo;
|
OctreeElement* childTwo;
|
||||||
OctreeElement* childThree;
|
OctreeElement* childThree;
|
||||||
|
|
||||||
// Get the existing two children out of their encoding...
|
// Get the existing two children out of their encoding...
|
||||||
retrieveTwoChildren(childOne, childTwo);
|
retrieveTwoChildren(childOne, childTwo);
|
||||||
|
|
||||||
// determine order of the existing children
|
// determine order of the existing children
|
||||||
int indexOne = getNthBit(previousChildMask, 1);
|
int indexOne = getNthBit(previousChildMask, 1);
|
||||||
|
@ -870,7 +870,7 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
|
||||||
storeThreeChildren(childOne, childTwo, childThree);
|
storeThreeChildren(childOne, childTwo, childThree);
|
||||||
} else if (previousChildCount == 3 && newChildCount == 2) {
|
} else if (previousChildCount == 3 && newChildCount == 2) {
|
||||||
// If we had 3 children, and now have 2, then we know we are going from an external case to a potential internal case
|
// If we had 3 children, and now have 2, then we know we are going from an external case to a potential internal case
|
||||||
|
|
||||||
// We need to determine which children we had, and which one we got rid of...
|
// We need to determine which children we had, and which one we got rid of...
|
||||||
int indexOne = getNthBit(previousChildMask, 1);
|
int indexOne = getNthBit(previousChildMask, 1);
|
||||||
int indexTwo = getNthBit(previousChildMask, 2);
|
int indexTwo = getNthBit(previousChildMask, 2);
|
||||||
|
@ -882,8 +882,8 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
|
||||||
OctreeElement* childTwo;
|
OctreeElement* childTwo;
|
||||||
OctreeElement* childThree;
|
OctreeElement* childThree;
|
||||||
|
|
||||||
// Get the existing two children out of their encoding...
|
// Get the existing two children out of their encoding...
|
||||||
retrieveThreeChildren(childOne, childTwo, childThree);
|
retrieveThreeChildren(childOne, childTwo, childThree);
|
||||||
|
|
||||||
if (removeChildOne) {
|
if (removeChildOne) {
|
||||||
childOne = childTwo;
|
childOne = childTwo;
|
||||||
|
@ -894,10 +894,10 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
|
||||||
// removing child three, nothing to do.
|
// removing child three, nothing to do.
|
||||||
}
|
}
|
||||||
|
|
||||||
storeTwoChildren(childOne, childTwo);
|
storeTwoChildren(childOne, childTwo);
|
||||||
} else if (previousChildCount == 3 && newChildCount == 3) {
|
} else if (previousChildCount == 3 && newChildCount == 3) {
|
||||||
// If we had 3 children, and now have 3, then we need to determine which item we're replacing...
|
// If we had 3 children, and now have 3, then we need to determine which item we're replacing...
|
||||||
|
|
||||||
// We need to determine which children we had, and which one we got rid of...
|
// We need to determine which children we had, and which one we got rid of...
|
||||||
int indexOne = getNthBit(previousChildMask, 1);
|
int indexOne = getNthBit(previousChildMask, 1);
|
||||||
int indexTwo = getNthBit(previousChildMask, 2);
|
int indexTwo = getNthBit(previousChildMask, 2);
|
||||||
|
@ -909,8 +909,8 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
|
||||||
OctreeElement* childTwo;
|
OctreeElement* childTwo;
|
||||||
OctreeElement* childThree;
|
OctreeElement* childThree;
|
||||||
|
|
||||||
// Get the existing two children out of their encoding...
|
// Get the existing two children out of their encoding...
|
||||||
retrieveThreeChildren(childOne, childTwo, childThree);
|
retrieveThreeChildren(childOne, childTwo, childThree);
|
||||||
|
|
||||||
if (replaceChildOne) {
|
if (replaceChildOne) {
|
||||||
childOne = child;
|
childOne = child;
|
||||||
|
@ -930,8 +930,8 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
|
||||||
OctreeElement* childThree;
|
OctreeElement* childThree;
|
||||||
OctreeElement* childFour;
|
OctreeElement* childFour;
|
||||||
|
|
||||||
// Get the existing two children out of their encoding...
|
// Get the existing two children out of their encoding...
|
||||||
retrieveThreeChildren(childOne, childTwo, childThree);
|
retrieveThreeChildren(childOne, childTwo, childThree);
|
||||||
|
|
||||||
// determine order of the existing children
|
// determine order of the existing children
|
||||||
int indexOne = getNthBit(previousChildMask, 1);
|
int indexOne = getNthBit(previousChildMask, 1);
|
||||||
|
@ -959,9 +959,9 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
|
||||||
const int newChildCount = 4;
|
const int newChildCount = 4;
|
||||||
_children.external = new OctreeElement*[newChildCount];
|
_children.external = new OctreeElement*[newChildCount];
|
||||||
memset(_children.external, 0, sizeof(OctreeElement*) * newChildCount);
|
memset(_children.external, 0, sizeof(OctreeElement*) * newChildCount);
|
||||||
|
|
||||||
_externalChildrenMemoryUsage += newChildCount * sizeof(OctreeElement*);
|
_externalChildrenMemoryUsage += newChildCount * sizeof(OctreeElement*);
|
||||||
|
|
||||||
_children.external[0] = childOne;
|
_children.external[0] = childOne;
|
||||||
_children.external[1] = childTwo;
|
_children.external[1] = childTwo;
|
||||||
_children.external[2] = childThree;
|
_children.external[2] = childThree;
|
||||||
|
@ -970,7 +970,7 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
|
||||||
} else if (previousChildCount == 4 && newChildCount == 3) {
|
} else if (previousChildCount == 4 && newChildCount == 3) {
|
||||||
// If we had 4 children, and now have 3, then we know we are going from an external case to a potential internal case
|
// If we had 4 children, and now have 3, then we know we are going from an external case to a potential internal case
|
||||||
//assert(_children.external && _childrenExternal && previousChildCount == 4);
|
//assert(_children.external && _childrenExternal && previousChildCount == 4);
|
||||||
|
|
||||||
// We need to determine which children we had, and which one we got rid of...
|
// We need to determine which children we had, and which one we got rid of...
|
||||||
int indexOne = getNthBit(previousChildMask, 1);
|
int indexOne = getNthBit(previousChildMask, 1);
|
||||||
int indexTwo = getNthBit(previousChildMask, 2);
|
int indexTwo = getNthBit(previousChildMask, 2);
|
||||||
|
@ -1008,7 +1008,7 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
|
||||||
} else if (previousChildCount == newChildCount) {
|
} else if (previousChildCount == newChildCount) {
|
||||||
//assert(_children.external && _childrenExternal && previousChildCount >= 4);
|
//assert(_children.external && _childrenExternal && previousChildCount >= 4);
|
||||||
//assert(previousChildCount == newChildCount);
|
//assert(previousChildCount == newChildCount);
|
||||||
|
|
||||||
// 4 or more children, one item being replaced, we know we're stored externally, we just need to find the one
|
// 4 or more children, one item being replaced, we know we're stored externally, we just need to find the one
|
||||||
// that needs to be replaced and replace it.
|
// that needs to be replaced and replace it.
|
||||||
for (int ordinal = 1; ordinal <= 8; ordinal++) {
|
for (int ordinal = 1; ordinal <= 8; ordinal++) {
|
||||||
|
@ -1024,12 +1024,12 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
|
||||||
// Growing case... previous must be 4 or greater
|
// Growing case... previous must be 4 or greater
|
||||||
//assert(_children.external && _childrenExternal && previousChildCount >= 4);
|
//assert(_children.external && _childrenExternal && previousChildCount >= 4);
|
||||||
//assert(previousChildCount == newChildCount-1);
|
//assert(previousChildCount == newChildCount-1);
|
||||||
|
|
||||||
// 4 or more children, one item being added, we know we're stored externally, we just figure out where to insert
|
// 4 or more children, one item being added, we know we're stored externally, we just figure out where to insert
|
||||||
// this child pointer into our external list
|
// this child pointer into our external list
|
||||||
OctreeElement** newExternalList = new OctreeElement*[newChildCount];
|
OctreeElement** newExternalList = new OctreeElement*[newChildCount];
|
||||||
memset(newExternalList, 0, sizeof(OctreeElement*) * newChildCount);
|
memset(newExternalList, 0, sizeof(OctreeElement*) * newChildCount);
|
||||||
|
|
||||||
int copiedCount = 0;
|
int copiedCount = 0;
|
||||||
for (int ordinal = 1; ordinal <= newChildCount; ordinal++) {
|
for (int ordinal = 1; ordinal <= newChildCount; ordinal++) {
|
||||||
int index = getNthBit(previousChildMask, ordinal);
|
int index = getNthBit(previousChildMask, ordinal);
|
||||||
|
@ -1037,10 +1037,10 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
|
||||||
newExternalList[ordinal - 1] = _children.external[ordinal - 1];
|
newExternalList[ordinal - 1] = _children.external[ordinal - 1];
|
||||||
copiedCount++;
|
copiedCount++;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// insert our new child here...
|
// insert our new child here...
|
||||||
newExternalList[ordinal - 1] = child;
|
newExternalList[ordinal - 1] = child;
|
||||||
|
|
||||||
// if we didn't copy all of our previous children, then we need to
|
// if we didn't copy all of our previous children, then we need to
|
||||||
if (copiedCount < previousChildCount) {
|
if (copiedCount < previousChildCount) {
|
||||||
// our child needs to be inserted before this index, and everything else pushed out...
|
// our child needs to be inserted before this index, and everything else pushed out...
|
||||||
|
@ -1060,10 +1060,10 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
|
||||||
//assert(_children.external && _childrenExternal && previousChildCount >= 4);
|
//assert(_children.external && _childrenExternal && previousChildCount >= 4);
|
||||||
//assert(previousChildCount == newChildCount+1);
|
//assert(previousChildCount == newChildCount+1);
|
||||||
|
|
||||||
// 4 or more children, one item being removed, we know we're stored externally, we just figure out which
|
// 4 or more children, one item being removed, we know we're stored externally, we just figure out which
|
||||||
// item to remove from our external list
|
// item to remove from our external list
|
||||||
OctreeElement** newExternalList = new OctreeElement*[newChildCount];
|
OctreeElement** newExternalList = new OctreeElement*[newChildCount];
|
||||||
|
|
||||||
for (int ordinal = 1; ordinal <= previousChildCount; ordinal++) {
|
for (int ordinal = 1; ordinal <= previousChildCount; ordinal++) {
|
||||||
int index = getNthBit(previousChildMask, ordinal);
|
int index = getNthBit(previousChildMask, ordinal);
|
||||||
//assert(index != -1);
|
//assert(index != -1);
|
||||||
|
@ -1090,7 +1090,7 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
|
||||||
if (getChildCount() == 4 && _childrenExternal && _children.external) {
|
if (getChildCount() == 4 && _childrenExternal && _children.external) {
|
||||||
checkStoreFourChildren(_children.external[0], _children.external[1], _children.external[2], _children.external[3]);
|
checkStoreFourChildren(_children.external[0], _children.external[1], _children.external[2], _children.external[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAS_AUDIT_CHILDREN
|
#ifdef HAS_AUDIT_CHILDREN
|
||||||
_childrenArray[childIndex] = child;
|
_childrenArray[childIndex] = child;
|
||||||
|
@ -1104,11 +1104,11 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
|
||||||
OctreeElement* OctreeElement::addChildAtIndex(int childIndex) {
|
OctreeElement* OctreeElement::addChildAtIndex(int childIndex) {
|
||||||
OctreeElement* childAt = getChildAtIndex(childIndex);
|
OctreeElement* childAt = getChildAtIndex(childIndex);
|
||||||
if (!childAt) {
|
if (!childAt) {
|
||||||
// before adding a child, see if we're currently a leaf
|
// before adding a child, see if we're currently a leaf
|
||||||
if (isLeaf()) {
|
if (isLeaf()) {
|
||||||
_voxelNodeLeafCount--;
|
_voxelNodeLeafCount--;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char* newChildCode = childOctalCode(getOctalCode(), childIndex);
|
unsigned char* newChildCode = childOctalCode(getOctalCode(), childIndex);
|
||||||
childAt = createNewElement(newChildCode);
|
childAt = createNewElement(newChildCode);
|
||||||
setChildAtIndex(childIndex, childAt);
|
setChildAtIndex(childIndex, childAt);
|
||||||
|
@ -1133,11 +1133,15 @@ bool OctreeElement::safeDeepDeleteChildAtIndex(int childIndex, int recursionCoun
|
||||||
if (!childToDelete->isLeaf()) {
|
if (!childToDelete->isLeaf()) {
|
||||||
// delete all it's children
|
// delete all it's children
|
||||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||||
deleteApproved = childToDelete->safeDeepDeleteChildAtIndex(i,recursionCount+1);
|
if (childToDelete->getChildAtIndex(i)) {
|
||||||
if (!deleteApproved) {
|
deleteApproved = childToDelete->safeDeepDeleteChildAtIndex(i,recursionCount+1);
|
||||||
break; // no point in continuing...
|
if (!deleteApproved) {
|
||||||
|
break; // no point in continuing...
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
deleteApproved = true; // because we got here after checking that delete was approved
|
||||||
}
|
}
|
||||||
if (deleteApproved) {
|
if (deleteApproved) {
|
||||||
deleteChildAtIndex(childIndex);
|
deleteChildAtIndex(childIndex);
|
||||||
|
@ -1155,14 +1159,14 @@ void OctreeElement::printDebugDetails(const char* label) const {
|
||||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||||
OctreeElement* childAt = getChildAtIndex(i);
|
OctreeElement* childAt = getChildAtIndex(i);
|
||||||
if (childAt) {
|
if (childAt) {
|
||||||
setAtBit(childBits,i);
|
setAtBit(childBits,i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug("%s - Voxel at corner=(%f,%f,%f) size=%f\n isLeaf=%s isDirty=%s shouldRender=%s\n children=", label,
|
qDebug("%s - Voxel at corner=(%f,%f,%f) size=%f\n isLeaf=%s isDirty=%s shouldRender=%s\n children=", label,
|
||||||
_box.getCorner().x, _box.getCorner().y, _box.getCorner().z, _box.getScale(),
|
_box.getCorner().x, _box.getCorner().y, _box.getCorner().z, _box.getScale(),
|
||||||
debug::valueOf(isLeaf()), debug::valueOf(isDirty()), debug::valueOf(getShouldRender()));
|
debug::valueOf(isLeaf()), debug::valueOf(isDirty()), debug::valueOf(getShouldRender()));
|
||||||
|
|
||||||
outputBits(childBits, false);
|
outputBits(childBits, false);
|
||||||
qDebug("\n octalCode=");
|
qDebug("\n octalCode=");
|
||||||
printOctalCode(getOctalCode());
|
printOctalCode(getOctalCode());
|
||||||
|
@ -1188,10 +1192,10 @@ ViewFrustum::location OctreeElement::inFrustum(const ViewFrustum& viewFrustum) c
|
||||||
// There are two types of nodes for which we want to "render"
|
// There are two types of nodes for which we want to "render"
|
||||||
// 1) Leaves that are in the LOD
|
// 1) Leaves that are in the LOD
|
||||||
// 2) Non-leaves are more complicated though... usually you don't want to render them, but if their children
|
// 2) Non-leaves are more complicated though... usually you don't want to render them, but if their children
|
||||||
// wouldn't be rendered, then you do want to render them. But sometimes they have some children that ARE
|
// wouldn't be rendered, then you do want to render them. But sometimes they have some children that ARE
|
||||||
// in the LOD, and others that are not. In this case we want to render the parent, and none of the children.
|
// in the LOD, and others that are not. In this case we want to render the parent, and none of the children.
|
||||||
//
|
//
|
||||||
// Since, if we know the camera position and orientation, we can know which of the corners is the "furthest"
|
// Since, if we know the camera position and orientation, we can know which of the corners is the "furthest"
|
||||||
// corner. We can use we can use this corner as our "voxel position" to do our distance calculations off of.
|
// corner. We can use we can use this corner as our "voxel position" to do our distance calculations off of.
|
||||||
// By doing this, we don't need to test each child voxel's position vs the LOD boundary
|
// By doing this, we don't need to test each child voxel's position vs the LOD boundary
|
||||||
bool OctreeElement::calculateShouldRender(const ViewFrustum* viewFrustum, float voxelScaleSize, int boundaryLevelAdjust) const {
|
bool OctreeElement::calculateShouldRender(const ViewFrustum* viewFrustum, float voxelScaleSize, int boundaryLevelAdjust) const {
|
||||||
|
@ -1285,7 +1289,7 @@ void OctreeElement::notifyUpdateHooks() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OctreeElement::findSpherePenetration(const glm::vec3& center, float radius,
|
bool OctreeElement::findSpherePenetration(const glm::vec3& center, float radius,
|
||||||
glm::vec3& penetration, void** penetratedObject) const {
|
glm::vec3& penetration, void** penetratedObject) const {
|
||||||
return _box.findSpherePenetration(center, radius, penetration);
|
return _box.findSpherePenetration(center, radius, penetration);
|
||||||
}
|
}
|
||||||
|
@ -1307,7 +1311,7 @@ OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float
|
||||||
}
|
}
|
||||||
// otherwise, we need to find which of our children we should recurse
|
// otherwise, we need to find which of our children we should recurse
|
||||||
glm::vec3 ourCenter = _box.calcCenter();
|
glm::vec3 ourCenter = _box.calcCenter();
|
||||||
|
|
||||||
int childIndex = CHILD_UNKNOWN;
|
int childIndex = CHILD_UNKNOWN;
|
||||||
// left half
|
// left half
|
||||||
if (x > ourCenter.x) {
|
if (x > ourCenter.x) {
|
||||||
|
@ -1352,13 +1356,13 @@ OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now, check if we have a child at that location
|
// Now, check if we have a child at that location
|
||||||
child = getChildAtIndex(childIndex);
|
child = getChildAtIndex(childIndex);
|
||||||
if (!child) {
|
if (!child) {
|
||||||
child = addChildAtIndex(childIndex);
|
child = addChildAtIndex(childIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we have the child to recurse down, let it answer the original question...
|
// Now that we have the child to recurse down, let it answer the original question...
|
||||||
return child->getOrCreateChildElementAt(x, y, z, s);
|
return child->getOrCreateChildElementAt(x, y, z, s);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,39 +7,43 @@
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <QtScript/QScriptEngine>
|
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
|
|
||||||
|
#include <Octree.h>
|
||||||
#include <RegisteredMetaTypes.h>
|
#include <RegisteredMetaTypes.h>
|
||||||
#include <SharedUtil.h> // usecTimestampNow()
|
#include <SharedUtil.h> // usecTimestampNow()
|
||||||
#include <Octree.h>
|
|
||||||
|
|
||||||
#include <VoxelsScriptingInterface.h>
|
#include <VoxelsScriptingInterface.h>
|
||||||
#include "ParticlesScriptingInterface.h"
|
|
||||||
|
|
||||||
|
// This is not ideal, but adding script-engine as a linked library, will cause a circular reference
|
||||||
|
// I'm open to other potential solutions. Could we change cmake to allow libraries to reference each others
|
||||||
|
// headers, but not link to each other, this is essentially what this construct is doing, but would be
|
||||||
|
// better to add includes to the include path, but not link
|
||||||
|
#include "../../script-engine/src/ScriptEngine.h"
|
||||||
|
|
||||||
|
#include "ParticlesScriptingInterface.h"
|
||||||
#include "Particle.h"
|
#include "Particle.h"
|
||||||
|
|
||||||
uint32_t Particle::_nextID = 0;
|
uint32_t Particle::_nextID = 0;
|
||||||
VoxelsScriptingInterface* Particle::_voxelsScriptingInterface = NULL;
|
VoxelEditPacketSender* Particle::_voxelEditSender = NULL;
|
||||||
ParticlesScriptingInterface* Particle::_particlesScriptingInterface = NULL;
|
ParticleEditPacketSender* Particle::_particleEditSender = NULL;
|
||||||
|
|
||||||
|
|
||||||
Particle::Particle(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, glm::vec3 gravity,
|
Particle::Particle(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, glm::vec3 gravity,
|
||||||
float damping, bool inHand, QString updateScript, uint32_t id) {
|
float damping, bool inHand, QString updateScript, uint32_t id) {
|
||||||
|
|
||||||
init(position, radius, color, velocity, gravity, damping, inHand, updateScript, id);
|
init(position, radius, color, velocity, gravity, damping, inHand, updateScript, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Particle::Particle() {
|
Particle::Particle() {
|
||||||
rgbColor noColor = { 0, 0, 0 };
|
rgbColor noColor = { 0, 0, 0 };
|
||||||
init(glm::vec3(0,0,0), 0, noColor, glm::vec3(0,0,0),
|
init(glm::vec3(0,0,0), 0, noColor, glm::vec3(0,0,0),
|
||||||
DEFAULT_GRAVITY, DEFAULT_DAMPING, NOT_IN_HAND, DEFAULT_SCRIPT, NEW_PARTICLE);
|
DEFAULT_GRAVITY, DEFAULT_DAMPING, NOT_IN_HAND, DEFAULT_SCRIPT, NEW_PARTICLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
Particle::~Particle() {
|
Particle::~Particle() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, glm::vec3 gravity,
|
void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, glm::vec3 gravity,
|
||||||
float damping, bool inHand, QString updateScript, uint32_t id) {
|
float damping, bool inHand, QString updateScript, uint32_t id) {
|
||||||
if (id == NEW_PARTICLE) {
|
if (id == NEW_PARTICLE) {
|
||||||
_id = _nextID;
|
_id = _nextID;
|
||||||
|
@ -51,7 +55,7 @@ void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3
|
||||||
_lastEdited = now;
|
_lastEdited = now;
|
||||||
_lastUpdated = now;
|
_lastUpdated = now;
|
||||||
_created = now; // will get updated as appropriate in setLifetime()
|
_created = now; // will get updated as appropriate in setLifetime()
|
||||||
|
|
||||||
_position = position;
|
_position = position;
|
||||||
_radius = radius;
|
_radius = radius;
|
||||||
memcpy(_color, color, sizeof(_color));
|
memcpy(_color, color, sizeof(_color));
|
||||||
|
@ -215,7 +219,7 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef
|
||||||
_script = tempString;
|
_script = tempString;
|
||||||
dataAt += scriptLength;
|
dataAt += scriptLength;
|
||||||
bytesRead += scriptLength;
|
bytesRead += scriptLength;
|
||||||
|
|
||||||
//printf("Particle::readParticleDataFromBuffer()... "); debugDump();
|
//printf("Particle::readParticleDataFromBuffer()... "); debugDump();
|
||||||
}
|
}
|
||||||
return bytesRead;
|
return bytesRead;
|
||||||
|
@ -227,11 +231,11 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe
|
||||||
unsigned char* dataAt = data;
|
unsigned char* dataAt = data;
|
||||||
processedBytes = 0;
|
processedBytes = 0;
|
||||||
|
|
||||||
// the first part of the data is our octcode...
|
// the first part of the data is our octcode...
|
||||||
int octets = numberOfThreeBitSectionsInCode(data);
|
int octets = numberOfThreeBitSectionsInCode(data);
|
||||||
int lengthOfOctcode = bytesRequiredForCodeLength(octets);
|
int lengthOfOctcode = bytesRequiredForCodeLength(octets);
|
||||||
|
|
||||||
// we don't actually do anything with this octcode...
|
// we don't actually do anything with this octcode...
|
||||||
dataAt += lengthOfOctcode;
|
dataAt += lengthOfOctcode;
|
||||||
processedBytes += lengthOfOctcode;
|
processedBytes += lengthOfOctcode;
|
||||||
|
|
||||||
|
@ -240,7 +244,7 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe
|
||||||
memcpy(&editID, dataAt, sizeof(editID));
|
memcpy(&editID, dataAt, sizeof(editID));
|
||||||
dataAt += sizeof(editID);
|
dataAt += sizeof(editID);
|
||||||
processedBytes += sizeof(editID);
|
processedBytes += sizeof(editID);
|
||||||
|
|
||||||
// special case for handling "new" particles
|
// special case for handling "new" particles
|
||||||
if (editID == NEW_PARTICLE) {
|
if (editID == NEW_PARTICLE) {
|
||||||
// If this is a NEW_PARTICLE, then we assume that there's an additional uint32_t creatorToken, that
|
// If this is a NEW_PARTICLE, then we assume that there's an additional uint32_t creatorToken, that
|
||||||
|
@ -251,19 +255,19 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe
|
||||||
processedBytes += sizeof(creatorTokenID);
|
processedBytes += sizeof(creatorTokenID);
|
||||||
newParticle.setCreatorTokenID(creatorTokenID);
|
newParticle.setCreatorTokenID(creatorTokenID);
|
||||||
newParticle._newlyCreated = true;
|
newParticle._newlyCreated = true;
|
||||||
|
|
||||||
newParticle.setLifetime(0); // this guy is new!
|
newParticle.setLifetime(0); // this guy is new!
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
newParticle._id = editID;
|
newParticle._id = editID;
|
||||||
newParticle._newlyCreated = false;
|
newParticle._newlyCreated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// lastEdited
|
// lastEdited
|
||||||
memcpy(&newParticle._lastEdited, dataAt, sizeof(newParticle._lastEdited));
|
memcpy(&newParticle._lastEdited, dataAt, sizeof(newParticle._lastEdited));
|
||||||
dataAt += sizeof(newParticle._lastEdited);
|
dataAt += sizeof(newParticle._lastEdited);
|
||||||
processedBytes += sizeof(newParticle._lastEdited);
|
processedBytes += sizeof(newParticle._lastEdited);
|
||||||
|
|
||||||
// radius
|
// radius
|
||||||
memcpy(&newParticle._radius, dataAt, sizeof(newParticle._radius));
|
memcpy(&newParticle._radius, dataAt, sizeof(newParticle._radius));
|
||||||
dataAt += sizeof(newParticle._radius);
|
dataAt += sizeof(newParticle._radius);
|
||||||
|
@ -283,12 +287,12 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe
|
||||||
memcpy(&newParticle._velocity, dataAt, sizeof(newParticle._velocity));
|
memcpy(&newParticle._velocity, dataAt, sizeof(newParticle._velocity));
|
||||||
dataAt += sizeof(newParticle._velocity);
|
dataAt += sizeof(newParticle._velocity);
|
||||||
processedBytes += sizeof(newParticle._velocity);
|
processedBytes += sizeof(newParticle._velocity);
|
||||||
|
|
||||||
// gravity
|
// gravity
|
||||||
memcpy(&newParticle._gravity, dataAt, sizeof(newParticle._gravity));
|
memcpy(&newParticle._gravity, dataAt, sizeof(newParticle._gravity));
|
||||||
dataAt += sizeof(newParticle._gravity);
|
dataAt += sizeof(newParticle._gravity);
|
||||||
processedBytes += sizeof(newParticle._gravity);
|
processedBytes += sizeof(newParticle._gravity);
|
||||||
|
|
||||||
// damping
|
// damping
|
||||||
memcpy(&newParticle._damping, dataAt, sizeof(newParticle._damping));
|
memcpy(&newParticle._damping, dataAt, sizeof(newParticle._damping));
|
||||||
dataAt += sizeof(newParticle._damping);
|
dataAt += sizeof(newParticle._damping);
|
||||||
|
@ -311,11 +315,11 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe
|
||||||
|
|
||||||
const bool wantDebugging = false;
|
const bool wantDebugging = false;
|
||||||
if (wantDebugging) {
|
if (wantDebugging) {
|
||||||
printf("Particle::fromEditPacket()...\n");
|
printf("Particle::fromEditPacket()...\n");
|
||||||
printf(" Particle id in packet:%u\n", editID);
|
printf(" Particle id in packet:%u\n", editID);
|
||||||
newParticle.debugDump();
|
newParticle.debugDump();
|
||||||
}
|
}
|
||||||
|
|
||||||
return newParticle;
|
return newParticle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,7 +333,7 @@ void Particle::debugDump() const {
|
||||||
printf(" color:%d,%d,%d\n", _color[0], _color[1], _color[2]);
|
printf(" color:%d,%d,%d\n", _color[0], _color[1], _color[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count, const ParticleDetail* details,
|
bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count, const ParticleDetail* details,
|
||||||
unsigned char* bufferOut, int sizeIn, int& sizeOut) {
|
unsigned char* bufferOut, int sizeIn, int& sizeOut) {
|
||||||
|
|
||||||
bool success = true; // assume the best
|
bool success = true; // assume the best
|
||||||
|
@ -338,13 +342,13 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count,
|
||||||
|
|
||||||
for (int i = 0; i < count && success; i++) {
|
for (int i = 0; i < count && success; i++) {
|
||||||
// get the octal code for the particle
|
// get the octal code for the particle
|
||||||
unsigned char* octcode = pointToOctalCode(details[i].position.x, details[i].position.y,
|
unsigned char* octcode = pointToOctalCode(details[i].position.x, details[i].position.y,
|
||||||
details[i].position.z, details[i].radius);
|
details[i].position.z, details[i].radius);
|
||||||
|
|
||||||
int octets = numberOfThreeBitSectionsInCode(octcode);
|
int octets = numberOfThreeBitSectionsInCode(octcode);
|
||||||
int lengthOfOctcode = bytesRequiredForCodeLength(octets);
|
int lengthOfOctcode = bytesRequiredForCodeLength(octets);
|
||||||
int lenfthOfEditData = lengthOfOctcode + expectedEditMessageBytes();
|
int lenfthOfEditData = lengthOfOctcode + expectedEditMessageBytes();
|
||||||
|
|
||||||
// make sure we have room to copy this particle
|
// make sure we have room to copy this particle
|
||||||
if (sizeOut + lenfthOfEditData > sizeIn) {
|
if (sizeOut + lenfthOfEditData > sizeIn) {
|
||||||
success = false;
|
success = false;
|
||||||
|
@ -353,9 +357,9 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count,
|
||||||
memcpy(copyAt, octcode, lengthOfOctcode);
|
memcpy(copyAt, octcode, lengthOfOctcode);
|
||||||
copyAt += lengthOfOctcode;
|
copyAt += lengthOfOctcode;
|
||||||
sizeOut += lengthOfOctcode;
|
sizeOut += lengthOfOctcode;
|
||||||
|
|
||||||
// Now add our edit content details...
|
// Now add our edit content details...
|
||||||
|
|
||||||
// id
|
// id
|
||||||
memcpy(copyAt, &details[i].id, sizeof(details[i].id));
|
memcpy(copyAt, &details[i].id, sizeof(details[i].id));
|
||||||
copyAt += sizeof(details[i].id);
|
copyAt += sizeof(details[i].id);
|
||||||
|
@ -419,7 +423,7 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count,
|
||||||
sizeOut += scriptLength;
|
sizeOut += scriptLength;
|
||||||
|
|
||||||
bool wantDebugging = false;
|
bool wantDebugging = false;
|
||||||
if (wantDebugging) {
|
if (wantDebugging) {
|
||||||
printf("encodeParticleEditMessageDetails()....\n");
|
printf("encodeParticleEditMessageDetails()....\n");
|
||||||
printf("Particle id :%u\n", details[i].id);
|
printf("Particle id :%u\n", details[i].id);
|
||||||
printf(" nextID:%u\n", _nextID);
|
printf(" nextID:%u\n", _nextID);
|
||||||
|
@ -433,7 +437,7 @@ bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count,
|
||||||
}
|
}
|
||||||
|
|
||||||
// adjust any internal timestamps to fix clock skew for this server
|
// adjust any internal timestamps to fix clock skew for this server
|
||||||
void Particle::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew) {
|
void Particle::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew) {
|
||||||
unsigned char* dataAt = codeColorBuffer;
|
unsigned char* dataAt = codeColorBuffer;
|
||||||
int octets = numberOfThreeBitSectionsInCode(dataAt);
|
int octets = numberOfThreeBitSectionsInCode(dataAt);
|
||||||
int lengthOfOctcode = bytesRequiredForCodeLength(octets);
|
int lengthOfOctcode = bytesRequiredForCodeLength(octets);
|
||||||
|
@ -456,7 +460,7 @@ void Particle::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssiz
|
||||||
uint64_t lastEditedInServerTime = lastEditedInLocalTime + clockSkew;
|
uint64_t lastEditedInServerTime = lastEditedInLocalTime + clockSkew;
|
||||||
memcpy(dataAt, &lastEditedInServerTime, sizeof(lastEditedInServerTime));
|
memcpy(dataAt, &lastEditedInServerTime, sizeof(lastEditedInServerTime));
|
||||||
const bool wantDebug = false;
|
const bool wantDebug = false;
|
||||||
if (wantDebug) {
|
if (wantDebug) {
|
||||||
qDebug("Particle::adjustEditPacketForClockSkew()...\n");
|
qDebug("Particle::adjustEditPacketForClockSkew()...\n");
|
||||||
qDebug() << " lastEditedInLocalTime: " << lastEditedInLocalTime << "\n";
|
qDebug() << " lastEditedInLocalTime: " << lastEditedInLocalTime << "\n";
|
||||||
qDebug() << " clockSkew: " << clockSkew << "\n";
|
qDebug() << " clockSkew: " << clockSkew << "\n";
|
||||||
|
@ -470,7 +474,7 @@ void Particle::update() {
|
||||||
float elapsed = static_cast<float>(now - _lastUpdated);
|
float elapsed = static_cast<float>(now - _lastUpdated);
|
||||||
_lastUpdated = now;
|
_lastUpdated = now;
|
||||||
float timeElapsed = elapsed / static_cast<float>(USECS_PER_SECOND);
|
float timeElapsed = elapsed / static_cast<float>(USECS_PER_SECOND);
|
||||||
|
|
||||||
// calculate our default shouldDie state... then allow script to change it if it wants...
|
// calculate our default shouldDie state... then allow script to change it if it wants...
|
||||||
float velocityScalar = glm::length(getVelocity());
|
float velocityScalar = glm::length(getVelocity());
|
||||||
const float STILL_MOVING = 0.05f / static_cast<float>(TREE_SCALE);
|
const float STILL_MOVING = 0.05f / static_cast<float>(TREE_SCALE);
|
||||||
|
@ -480,13 +484,13 @@ void Particle::update() {
|
||||||
bool isInHand = getInHand();
|
bool isInHand = getInHand();
|
||||||
bool shouldDie = getShouldDie() || (!isInHand && !isStillMoving && isReallyOld);
|
bool shouldDie = getShouldDie() || (!isInHand && !isStillMoving && isReallyOld);
|
||||||
setShouldDie(shouldDie);
|
setShouldDie(shouldDie);
|
||||||
|
|
||||||
runUpdateScript(); // allow the javascript to alter our state
|
runUpdateScript(); // allow the javascript to alter our state
|
||||||
|
|
||||||
// If the ball is in hand, it doesn't move or have gravity effect it
|
// If the ball is in hand, it doesn't move or have gravity effect it
|
||||||
if (!isInHand) {
|
if (!isInHand) {
|
||||||
_position += _velocity * timeElapsed;
|
_position += _velocity * timeElapsed;
|
||||||
|
|
||||||
// handle bounces off the ground...
|
// handle bounces off the ground...
|
||||||
if (_position.y <= 0) {
|
if (_position.y <= 0) {
|
||||||
_velocity = _velocity * glm::vec3(1,-1,1);
|
_velocity = _velocity * glm::vec3(1,-1,1);
|
||||||
|
@ -505,72 +509,59 @@ void Particle::update() {
|
||||||
|
|
||||||
void Particle::runUpdateScript() {
|
void Particle::runUpdateScript() {
|
||||||
if (!_script.isEmpty()) {
|
if (!_script.isEmpty()) {
|
||||||
|
ScriptEngine engine(_script); // no menu or controller interface...
|
||||||
|
|
||||||
QScriptEngine engine;
|
if (_voxelEditSender) {
|
||||||
|
engine.getVoxelsScriptingInterface()->setPacketSender(_voxelEditSender);
|
||||||
// register meta-type for glm::vec3 and rgbColor conversions
|
}
|
||||||
registerMetaTypes(&engine);
|
if (_particleEditSender) {
|
||||||
|
engine.getParticlesScriptingInterface()->setPacketSender(_particleEditSender);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the Particle object
|
||||||
ParticleScriptObject particleScriptable(this);
|
ParticleScriptObject particleScriptable(this);
|
||||||
QScriptValue particleValue = engine.newQObject(&particleScriptable);
|
engine.registerGlobalObject("Particle", &particleScriptable);
|
||||||
engine.globalObject().setProperty("Particle", particleValue);
|
|
||||||
|
// init and evaluate the script, but return so we can emit the collision
|
||||||
QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE));
|
engine.evaluate();
|
||||||
engine.globalObject().setProperty("TREE_SCALE", TREE_SCALE);
|
|
||||||
|
|
||||||
QScriptValue result = engine.evaluate(_script);
|
|
||||||
|
|
||||||
particleScriptable.emitUpdate();
|
particleScriptable.emitUpdate();
|
||||||
|
|
||||||
if (engine.hasUncaughtException()) {
|
if (_voxelEditSender) {
|
||||||
int line = engine.uncaughtExceptionLineNumber();
|
_voxelEditSender->releaseQueuedMessages();
|
||||||
qDebug() << "Uncaught exception at line" << line << ":" << result.toString() << "\n";
|
}
|
||||||
|
if (_particleEditSender) {
|
||||||
|
_particleEditSender->releaseQueuedMessages();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Particle::collisionWithParticle(Particle* other) {
|
void Particle::collisionWithParticle(Particle* other) {
|
||||||
if (!_script.isEmpty()) {
|
if (!_script.isEmpty()) {
|
||||||
|
ScriptEngine engine(_script); // no menu or controller interface...
|
||||||
|
|
||||||
QScriptEngine engine;
|
if (_voxelEditSender) {
|
||||||
|
engine.getVoxelsScriptingInterface()->setPacketSender(_voxelEditSender);
|
||||||
// register meta-type for glm::vec3 and rgbColor conversions
|
}
|
||||||
registerMetaTypes(&engine);
|
if (_particleEditSender) {
|
||||||
|
engine.getParticlesScriptingInterface()->setPacketSender(_particleEditSender);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the Particle object
|
||||||
ParticleScriptObject particleScriptable(this);
|
ParticleScriptObject particleScriptable(this);
|
||||||
QScriptValue particleValue = engine.newQObject(&particleScriptable);
|
engine.registerGlobalObject("Particle", &particleScriptable);
|
||||||
engine.globalObject().setProperty("Particle", particleValue);
|
|
||||||
|
|
||||||
QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE));
|
|
||||||
engine.globalObject().setProperty("TREE_SCALE", TREE_SCALE);
|
|
||||||
|
|
||||||
|
// init and evaluate the script, but return so we can emit the collision
|
||||||
|
engine.evaluate();
|
||||||
|
|
||||||
if (getVoxelsScriptingInterface()) {
|
|
||||||
QScriptValue voxelScripterValue = engine.newQObject(getVoxelsScriptingInterface());
|
|
||||||
engine.globalObject().setProperty("Voxels", voxelScripterValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getParticlesScriptingInterface()) {
|
|
||||||
QScriptValue particleScripterValue = engine.newQObject(getParticlesScriptingInterface());
|
|
||||||
engine.globalObject().setProperty("Particles", particleScripterValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
QScriptValue result = engine.evaluate(_script);
|
|
||||||
|
|
||||||
ParticleScriptObject otherParticleScriptable(other);
|
ParticleScriptObject otherParticleScriptable(other);
|
||||||
particleScriptable.emitCollisionWithParticle(&otherParticleScriptable);
|
particleScriptable.emitCollisionWithParticle(&otherParticleScriptable);
|
||||||
|
|
||||||
if (getVoxelsScriptingInterface()) {
|
if (_voxelEditSender) {
|
||||||
getVoxelsScriptingInterface()->getPacketSender()->releaseQueuedMessages();
|
_voxelEditSender->releaseQueuedMessages();
|
||||||
}
|
}
|
||||||
|
if (_particleEditSender) {
|
||||||
if (getParticlesScriptingInterface()) {
|
_particleEditSender->releaseQueuedMessages();
|
||||||
getParticlesScriptingInterface()->getPacketSender()->releaseQueuedMessages();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (engine.hasUncaughtException()) {
|
|
||||||
int line = engine.uncaughtExceptionLineNumber();
|
|
||||||
qDebug() << "Uncaught exception at line" << line << ":" << result.toString() << "\n";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -578,45 +569,32 @@ void Particle::collisionWithParticle(Particle* other) {
|
||||||
void Particle::collisionWithVoxel(VoxelDetail* voxelDetails) {
|
void Particle::collisionWithVoxel(VoxelDetail* voxelDetails) {
|
||||||
if (!_script.isEmpty()) {
|
if (!_script.isEmpty()) {
|
||||||
|
|
||||||
QScriptEngine engine;
|
ScriptEngine engine(_script); // no menu or controller interface...
|
||||||
|
|
||||||
// register meta-type for glm::vec3 and rgbColor conversions
|
// setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so
|
||||||
registerMetaTypes(&engine);
|
// we can use the same ones as our context.
|
||||||
|
if (_voxelEditSender) {
|
||||||
|
engine.getVoxelsScriptingInterface()->setPacketSender(_voxelEditSender);
|
||||||
|
}
|
||||||
|
if (_particleEditSender) {
|
||||||
|
engine.getParticlesScriptingInterface()->setPacketSender(_particleEditSender);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the Particle object
|
||||||
ParticleScriptObject particleScriptable(this);
|
ParticleScriptObject particleScriptable(this);
|
||||||
QScriptValue particleValue = engine.newQObject(&particleScriptable);
|
engine.registerGlobalObject("Particle", &particleScriptable);
|
||||||
engine.globalObject().setProperty("Particle", particleValue);
|
|
||||||
|
|
||||||
QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE));
|
|
||||||
engine.globalObject().setProperty("TREE_SCALE", TREE_SCALE);
|
|
||||||
|
|
||||||
|
// init and evaluate the script, but return so we can emit the collision
|
||||||
|
engine.evaluate();
|
||||||
|
|
||||||
if (getVoxelsScriptingInterface()) {
|
|
||||||
QScriptValue voxelScripterValue = engine.newQObject(getVoxelsScriptingInterface());
|
|
||||||
engine.globalObject().setProperty("Voxels", voxelScripterValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getParticlesScriptingInterface()) {
|
|
||||||
QScriptValue particleScripterValue = engine.newQObject(getParticlesScriptingInterface());
|
|
||||||
engine.globalObject().setProperty("Particles", particleScripterValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
QScriptValue result = engine.evaluate(_script);
|
|
||||||
|
|
||||||
VoxelDetailScriptObject voxelDetailsScriptable(voxelDetails);
|
VoxelDetailScriptObject voxelDetailsScriptable(voxelDetails);
|
||||||
particleScriptable.emitCollisionWithVoxel(&voxelDetailsScriptable);
|
particleScriptable.emitCollisionWithVoxel(&voxelDetailsScriptable);
|
||||||
|
|
||||||
if (getVoxelsScriptingInterface()) {
|
if (_voxelEditSender) {
|
||||||
getVoxelsScriptingInterface()->getPacketSender()->releaseQueuedMessages();
|
_voxelEditSender->releaseQueuedMessages();
|
||||||
}
|
}
|
||||||
|
if (_particleEditSender) {
|
||||||
if (getParticlesScriptingInterface()) {
|
_particleEditSender->releaseQueuedMessages();
|
||||||
getParticlesScriptingInterface()->getPacketSender()->releaseQueuedMessages();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (engine.hasUncaughtException()) {
|
|
||||||
int line = engine.uncaughtExceptionLineNumber();
|
|
||||||
qDebug() << "Uncaught exception at line" << line << ":" << result.toString() << "\n";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -625,7 +603,7 @@ void Particle::collisionWithVoxel(VoxelDetail* voxelDetails) {
|
||||||
|
|
||||||
void Particle::setLifetime(float lifetime) {
|
void Particle::setLifetime(float lifetime) {
|
||||||
uint64_t lifetimeInUsecs = lifetime * USECS_PER_SECOND;
|
uint64_t lifetimeInUsecs = lifetime * USECS_PER_SECOND;
|
||||||
_created = usecTimestampNow() - lifetimeInUsecs;
|
_created = usecTimestampNow() - lifetimeInUsecs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Particle::copyChangedProperties(const Particle& other) {
|
void Particle::copyChangedProperties(const Particle& other) {
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
|
|
||||||
class VoxelsScriptingInterface;
|
class VoxelsScriptingInterface;
|
||||||
class ParticlesScriptingInterface;
|
class ParticlesScriptingInterface;
|
||||||
|
class VoxelEditPacketSender;
|
||||||
|
class ParticleEditPacketSender;
|
||||||
|
|
||||||
|
|
||||||
const uint32_t NEW_PARTICLE = 0xFFFFFFFF;
|
const uint32_t NEW_PARTICLE = 0xFFFFFFFF;
|
||||||
|
@ -48,19 +50,19 @@ const bool IN_HAND = true; // it's in a hand
|
||||||
const bool NOT_IN_HAND = !IN_HAND; // it's not in a hand
|
const bool NOT_IN_HAND = !IN_HAND; // it's not in a hand
|
||||||
|
|
||||||
class Particle {
|
class Particle {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Particle();
|
Particle();
|
||||||
Particle(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity,
|
Particle(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity,
|
||||||
glm::vec3 gravity = DEFAULT_GRAVITY, float damping = DEFAULT_DAMPING, bool inHand = NOT_IN_HAND,
|
glm::vec3 gravity = DEFAULT_GRAVITY, float damping = DEFAULT_DAMPING, bool inHand = NOT_IN_HAND,
|
||||||
QString updateScript = DEFAULT_SCRIPT, uint32_t id = NEW_PARTICLE);
|
QString updateScript = DEFAULT_SCRIPT, uint32_t id = NEW_PARTICLE);
|
||||||
|
|
||||||
/// creates an NEW particle from an PACKET_TYPE_PARTICLE_ADD_OR_EDIT edit data buffer
|
/// creates an NEW particle from an PACKET_TYPE_PARTICLE_ADD_OR_EDIT edit data buffer
|
||||||
static Particle fromEditPacket(unsigned char* data, int length, int& processedBytes);
|
static Particle fromEditPacket(unsigned char* data, int length, int& processedBytes);
|
||||||
|
|
||||||
virtual ~Particle();
|
virtual ~Particle();
|
||||||
virtual void init(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity,
|
virtual void init(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity,
|
||||||
glm::vec3 gravity = DEFAULT_GRAVITY, float damping = DEFAULT_DAMPING, bool inHand = NOT_IN_HAND,
|
glm::vec3 gravity = DEFAULT_GRAVITY, float damping = DEFAULT_DAMPING, bool inHand = NOT_IN_HAND,
|
||||||
QString updateScript = DEFAULT_SCRIPT, uint32_t id = NEW_PARTICLE);
|
QString updateScript = DEFAULT_SCRIPT, uint32_t id = NEW_PARTICLE);
|
||||||
|
|
||||||
const glm::vec3& getPosition() const { return _position; }
|
const glm::vec3& getPosition() const { return _position; }
|
||||||
|
@ -71,7 +73,7 @@ public:
|
||||||
const glm::vec3& getGravity() const { return _gravity; }
|
const glm::vec3& getGravity() const { return _gravity; }
|
||||||
bool getInHand() const { return _inHand; }
|
bool getInHand() const { return _inHand; }
|
||||||
float getDamping() const { return _damping; }
|
float getDamping() const { return _damping; }
|
||||||
|
|
||||||
/// The last updated/simulated time of this particle from the time perspective of the authoritative server/source
|
/// The last updated/simulated time of this particle from the time perspective of the authoritative server/source
|
||||||
uint64_t getLastUpdated() const { return _lastUpdated; }
|
uint64_t getLastUpdated() const { return _lastUpdated; }
|
||||||
|
|
||||||
|
@ -91,9 +93,9 @@ public:
|
||||||
void setVelocity(const glm::vec3& value) { _velocity = value; }
|
void setVelocity(const glm::vec3& value) { _velocity = value; }
|
||||||
void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); }
|
void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); }
|
||||||
void setColor(const xColor& value) {
|
void setColor(const xColor& value) {
|
||||||
_color[RED_INDEX] = value.red;
|
_color[RED_INDEX] = value.red;
|
||||||
_color[GREEN_INDEX] = value.green;
|
_color[GREEN_INDEX] = value.green;
|
||||||
_color[BLUE_INDEX] = value.blue;
|
_color[BLUE_INDEX] = value.blue;
|
||||||
}
|
}
|
||||||
void setRadius(float value) { _radius = value; }
|
void setRadius(float value) { _radius = value; }
|
||||||
void setGravity(const glm::vec3& value) { _gravity = value; }
|
void setGravity(const glm::vec3& value) { _gravity = value; }
|
||||||
|
@ -102,15 +104,15 @@ public:
|
||||||
void setShouldDie(bool shouldDie) { _shouldDie = shouldDie; }
|
void setShouldDie(bool shouldDie) { _shouldDie = shouldDie; }
|
||||||
void setScript(QString updateScript) { _script = updateScript; }
|
void setScript(QString updateScript) { _script = updateScript; }
|
||||||
void setCreatorTokenID(uint32_t creatorTokenID) { _creatorTokenID = creatorTokenID; }
|
void setCreatorTokenID(uint32_t creatorTokenID) { _creatorTokenID = creatorTokenID; }
|
||||||
|
|
||||||
bool appendParticleData(OctreePacketData* packetData) const;
|
bool appendParticleData(OctreePacketData* packetData) const;
|
||||||
int readParticleDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args);
|
int readParticleDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args);
|
||||||
static int expectedBytes();
|
static int expectedBytes();
|
||||||
static int expectedEditMessageBytes();
|
static int expectedEditMessageBytes();
|
||||||
|
|
||||||
static bool encodeParticleEditMessageDetails(PACKET_TYPE command, int count, const ParticleDetail* details,
|
static bool encodeParticleEditMessageDetails(PACKET_TYPE command, int count, const ParticleDetail* details,
|
||||||
unsigned char* bufferOut, int sizeIn, int& sizeOut);
|
unsigned char* bufferOut, int sizeIn, int& sizeOut);
|
||||||
|
|
||||||
static void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew);
|
static void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew);
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
|
@ -118,22 +120,23 @@ public:
|
||||||
void collisionWithVoxel(VoxelDetail* voxel);
|
void collisionWithVoxel(VoxelDetail* voxel);
|
||||||
|
|
||||||
void debugDump() const;
|
void debugDump() const;
|
||||||
|
|
||||||
// similar to assignment/copy, but it handles keeping lifetime accurate
|
// similar to assignment/copy, but it handles keeping lifetime accurate
|
||||||
void copyChangedProperties(const Particle& other);
|
void copyChangedProperties(const Particle& other);
|
||||||
|
|
||||||
static VoxelsScriptingInterface* getVoxelsScriptingInterface() { return _voxelsScriptingInterface; }
|
|
||||||
static ParticlesScriptingInterface* getParticlesScriptingInterface() { return _particlesScriptingInterface; }
|
|
||||||
|
|
||||||
static void setVoxelsScriptingInterface(VoxelsScriptingInterface* interface)
|
static VoxelEditPacketSender* getVoxelEditPacketSender() { return _voxelEditSender; }
|
||||||
{ _voxelsScriptingInterface = interface; }
|
static ParticleEditPacketSender* getParticleEditPacketSender() { return _particleEditSender; }
|
||||||
|
|
||||||
static void setParticlesScriptingInterface(ParticlesScriptingInterface* interface)
|
static void setVoxelEditPacketSender(VoxelEditPacketSender* interface)
|
||||||
{ _particlesScriptingInterface = interface; }
|
{ _voxelEditSender = interface; }
|
||||||
|
|
||||||
|
static void setParticleEditPacketSender(ParticleEditPacketSender* interface)
|
||||||
|
{ _particleEditSender = interface; }
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static VoxelsScriptingInterface* _voxelsScriptingInterface;
|
static VoxelEditPacketSender* _voxelEditSender;
|
||||||
static ParticlesScriptingInterface* _particlesScriptingInterface;
|
static ParticleEditPacketSender* _particleEditSender;
|
||||||
|
|
||||||
void runUpdateScript();
|
void runUpdateScript();
|
||||||
static QScriptValue vec3toScriptValue(QScriptEngine *engine, const glm::vec3 &vec3);
|
static QScriptValue vec3toScriptValue(QScriptEngine *engine, const glm::vec3 &vec3);
|
||||||
|
@ -141,8 +144,8 @@ protected:
|
||||||
static QScriptValue xColorToScriptValue(QScriptEngine *engine, const xColor& color);
|
static QScriptValue xColorToScriptValue(QScriptEngine *engine, const xColor& color);
|
||||||
static void xColorFromScriptValue(const QScriptValue &object, xColor& color);
|
static void xColorFromScriptValue(const QScriptValue &object, xColor& color);
|
||||||
|
|
||||||
void setLifetime(float lifetime);
|
void setLifetime(float lifetime);
|
||||||
|
|
||||||
glm::vec3 _position;
|
glm::vec3 _position;
|
||||||
rgbColor _color;
|
rgbColor _color;
|
||||||
float _radius;
|
float _radius;
|
||||||
|
@ -184,7 +187,7 @@ public slots:
|
||||||
float getRadius() const { return _particle->getRadius(); }
|
float getRadius() const { return _particle->getRadius(); }
|
||||||
bool getShouldDie() { return _particle->getShouldDie(); }
|
bool getShouldDie() { return _particle->getShouldDie(); }
|
||||||
float getLifetime() const { return _particle->getLifetime(); }
|
float getLifetime() const { return _particle->getLifetime(); }
|
||||||
|
|
||||||
void setPosition(glm::vec3 value) { _particle->setPosition(value); }
|
void setPosition(glm::vec3 value) { _particle->setPosition(value); }
|
||||||
void setVelocity(glm::vec3 value) { _particle->setVelocity(value); }
|
void setVelocity(glm::vec3 value) { _particle->setVelocity(value); }
|
||||||
void setGravity(glm::vec3 value) { _particle->setGravity(value); }
|
void setGravity(glm::vec3 value) { _particle->setGravity(value); }
|
||||||
|
|
|
@ -19,12 +19,12 @@
|
||||||
#include "ParticleEditPacketSender.h"
|
#include "ParticleEditPacketSender.h"
|
||||||
#include "ParticleTree.h"
|
#include "ParticleTree.h"
|
||||||
|
|
||||||
ParticleCollisionSystem::ParticleCollisionSystem(ParticleEditPacketSender* packetSender,
|
ParticleCollisionSystem::ParticleCollisionSystem(ParticleEditPacketSender* packetSender,
|
||||||
ParticleTree* particles, VoxelTree* voxels, AbstractAudioInterface* audio, AvatarData* selfAvatar) {
|
ParticleTree* particles, VoxelTree* voxels, AbstractAudioInterface* audio, AvatarData* selfAvatar) {
|
||||||
init(packetSender, particles, voxels, audio, selfAvatar);
|
init(packetSender, particles, voxels, audio, selfAvatar);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParticleCollisionSystem::init(ParticleEditPacketSender* packetSender,
|
void ParticleCollisionSystem::init(ParticleEditPacketSender* packetSender,
|
||||||
ParticleTree* particles, VoxelTree* voxels, AbstractAudioInterface* audio, AvatarData* selfAvatar) {
|
ParticleTree* particles, VoxelTree* voxels, AbstractAudioInterface* audio, AvatarData* selfAvatar) {
|
||||||
_packetSender = packetSender;
|
_packetSender = packetSender;
|
||||||
_particles = particles;
|
_particles = particles;
|
||||||
|
@ -82,7 +82,7 @@ void ParticleCollisionSystem::updateCollisionWithVoxels(Particle* particle) {
|
||||||
penetration /= static_cast<float>(TREE_SCALE);
|
penetration /= static_cast<float>(TREE_SCALE);
|
||||||
updateCollisionSound(particle, penetration, COLLISION_FREQUENCY);
|
updateCollisionSound(particle, penetration, COLLISION_FREQUENCY);
|
||||||
applyHardCollision(particle, penetration, ELASTICITY, DAMPING);
|
applyHardCollision(particle, penetration, ELASTICITY, DAMPING);
|
||||||
|
|
||||||
delete voxelDetails; // cleanup returned details
|
delete voxelDetails; // cleanup returned details
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,16 +96,16 @@ void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particle) {
|
||||||
glm::vec3 penetration;
|
glm::vec3 penetration;
|
||||||
Particle* penetratedParticle;
|
Particle* penetratedParticle;
|
||||||
if (_particles->findSpherePenetration(center, radius, penetration, (void**)&penetratedParticle)) {
|
if (_particles->findSpherePenetration(center, radius, penetration, (void**)&penetratedParticle)) {
|
||||||
|
|
||||||
// let the particles run their collision scripts if they have them
|
// let the particles run their collision scripts if they have them
|
||||||
particle->collisionWithParticle(penetratedParticle);
|
particle->collisionWithParticle(penetratedParticle);
|
||||||
penetratedParticle->collisionWithParticle(particle);
|
penetratedParticle->collisionWithParticle(particle);
|
||||||
|
|
||||||
penetration /= static_cast<float>(TREE_SCALE);
|
penetration /= static_cast<float>(TREE_SCALE);
|
||||||
updateCollisionSound(particle, penetration, COLLISION_FREQUENCY);
|
updateCollisionSound(particle, penetration, COLLISION_FREQUENCY);
|
||||||
|
|
||||||
// apply a hard collision to both particles of half the penetration each
|
// apply a hard collision to both particles of half the penetration each
|
||||||
|
|
||||||
float particleShare, penetratedParticleShare;
|
float particleShare, penetratedParticleShare;
|
||||||
if (particle->getInHand() && penetratedParticle->getInHand()) {
|
if (particle->getInHand() && penetratedParticle->getInHand()) {
|
||||||
particleShare = 0.5f;
|
particleShare = 0.5f;
|
||||||
|
@ -140,7 +140,7 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
|
||||||
const float COLLISION_FREQUENCY = 0.5f;
|
const float COLLISION_FREQUENCY = 0.5f;
|
||||||
glm::vec3 penetration;
|
glm::vec3 penetration;
|
||||||
const PalmData* collidingPalm = NULL;
|
const PalmData* collidingPalm = NULL;
|
||||||
|
|
||||||
// first check the selfAvatar if set...
|
// first check the selfAvatar if set...
|
||||||
if (_selfAvatar) {
|
if (_selfAvatar) {
|
||||||
AvatarData* avatar = (AvatarData*)_selfAvatar;
|
AvatarData* avatar = (AvatarData*)_selfAvatar;
|
||||||
|
@ -158,7 +158,7 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
|
||||||
// apply a hard collision when ball collides with hand
|
// apply a hard collision when ball collides with hand
|
||||||
penetration /= static_cast<float>(TREE_SCALE);
|
penetration /= static_cast<float>(TREE_SCALE);
|
||||||
updateCollisionSound(particle, penetration, COLLISION_FREQUENCY);
|
updateCollisionSound(particle, penetration, COLLISION_FREQUENCY);
|
||||||
|
|
||||||
// determine if the palm that collided was moving, if so, then we add that palm velocity as well...
|
// determine if the palm that collided was moving, if so, then we add that palm velocity as well...
|
||||||
glm::vec3 addedVelocity = NO_ADDED_VELOCITY;
|
glm::vec3 addedVelocity = NO_ADDED_VELOCITY;
|
||||||
if (collidingPalm) {
|
if (collidingPalm) {
|
||||||
|
@ -185,7 +185,7 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
|
||||||
// TODO: dot collidingPalm and hand velocities and skip collision when they are moving apart.
|
// TODO: dot collidingPalm and hand velocities and skip collision when they are moving apart.
|
||||||
AvatarData* avatar = static_cast<AvatarData*>(node->getLinkedData());
|
AvatarData* avatar = static_cast<AvatarData*>(node->getLinkedData());
|
||||||
//printf("updateCollisionWithAvatars()...avatar=%p\n", avatar);
|
//printf("updateCollisionWithAvatars()...avatar=%p\n", avatar);
|
||||||
|
|
||||||
// check hands...
|
// check hands...
|
||||||
const HandData* handData = avatar->getHandData();
|
const HandData* handData = avatar->getHandData();
|
||||||
|
|
||||||
|
@ -215,15 +215,15 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ParticleCollisionSystem::applyHardCollision(Particle* particle, const glm::vec3& penetration,
|
void ParticleCollisionSystem::applyHardCollision(Particle* particle, const glm::vec3& penetration,
|
||||||
float elasticity, float damping, const glm::vec3& addedVelocity) {
|
float elasticity, float damping, const glm::vec3& addedVelocity) {
|
||||||
//
|
//
|
||||||
// Update the particle in response to a hard collision. Position will be reset exactly
|
// Update the particle in response to a hard collision. Position will be reset exactly
|
||||||
// to outside the colliding surface. Velocity will be modified according to elasticity.
|
// to outside the colliding surface. Velocity will be modified according to elasticity.
|
||||||
//
|
//
|
||||||
// if elasticity = 0.0, collision is inelastic (vel normal to collision is lost)
|
// if elasticity = 0.0, collision is inelastic (vel normal to collision is lost)
|
||||||
// if elasticity = 1.0, collision is 100% elastic.
|
// if elasticity = 1.0, collision is 100% elastic.
|
||||||
//
|
//
|
||||||
glm::vec3 position = particle->getPosition();
|
glm::vec3 position = particle->getPosition();
|
||||||
glm::vec3 velocity = particle->getVelocity();
|
glm::vec3 velocity = particle->getVelocity();
|
||||||
|
|
||||||
|
@ -249,15 +249,15 @@ void ParticleCollisionSystem::applyHardCollision(Particle* particle, const glm::
|
||||||
printf("ParticleCollisionSystem::applyHardCollision() particle id:%d new velocity:%f,%f,%f inHand:%s\n",
|
printf("ParticleCollisionSystem::applyHardCollision() particle id:%d new velocity:%f,%f,%f inHand:%s\n",
|
||||||
particle->getID(), velocity.x, velocity.y, velocity.z, debug::valueOf(particle->getInHand()));
|
particle->getID(), velocity.x, velocity.y, velocity.z, debug::valueOf(particle->getInHand()));
|
||||||
}
|
}
|
||||||
|
|
||||||
ParticleEditHandle particleEditHandle(_packetSender, _particles, particle->getID());
|
ParticleEditHandle particleEditHandle(_packetSender, _particles, particle->getID());
|
||||||
particleEditHandle.updateParticle(position, particle->getRadius(), particle->getXColor(), velocity,
|
particleEditHandle.updateParticle(position, particle->getRadius(), particle->getXColor(), velocity,
|
||||||
particle->getGravity(), particle->getDamping(), particle->getInHand(), particle->getScript());
|
particle->getGravity(), particle->getDamping(), particle->getInHand(), particle->getScript());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ParticleCollisionSystem::updateCollisionSound(Particle* particle, const glm::vec3 &penetration, float frequency) {
|
void ParticleCollisionSystem::updateCollisionSound(Particle* particle, const glm::vec3 &penetration, float frequency) {
|
||||||
|
|
||||||
// consider whether to have the collision make a sound
|
// consider whether to have the collision make a sound
|
||||||
const float AUDIBLE_COLLISION_THRESHOLD = 0.1f;
|
const float AUDIBLE_COLLISION_THRESHOLD = 0.1f;
|
||||||
const float COLLISION_LOUDNESS = 1.f;
|
const float COLLISION_LOUDNESS = 1.f;
|
||||||
|
@ -269,16 +269,16 @@ void ParticleCollisionSystem::updateCollisionSound(Particle* particle, const glm
|
||||||
// how do we want to handle this??
|
// how do we want to handle this??
|
||||||
//
|
//
|
||||||
glm::vec3 gravity = particle->getGravity() * static_cast<float>(TREE_SCALE);
|
glm::vec3 gravity = particle->getGravity() * static_cast<float>(TREE_SCALE);
|
||||||
|
|
||||||
if (glm::length(gravity) > EPSILON) {
|
if (glm::length(gravity) > EPSILON) {
|
||||||
// If gravity is on, remove the effect of gravity on velocity for this
|
// If gravity is on, remove the effect of gravity on velocity for this
|
||||||
// frame, so that we are not constantly colliding with the surface
|
// frame, so that we are not constantly colliding with the surface
|
||||||
velocity -= _scale * glm::length(gravity) * GRAVITY_EARTH * deltaTime * glm::normalize(gravity);
|
velocity -= _scale * glm::length(gravity) * GRAVITY_EARTH * deltaTime * glm::normalize(gravity);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
float velocityTowardCollision = glm::dot(velocity, glm::normalize(penetration));
|
float velocityTowardCollision = glm::dot(velocity, glm::normalize(penetration));
|
||||||
float velocityTangentToCollision = glm::length(velocity) - velocityTowardCollision;
|
float velocityTangentToCollision = glm::length(velocity) - velocityTowardCollision;
|
||||||
|
|
||||||
if (velocityTowardCollision > AUDIBLE_COLLISION_THRESHOLD) {
|
if (velocityTowardCollision > AUDIBLE_COLLISION_THRESHOLD) {
|
||||||
// Volume is proportional to collision velocity
|
// Volume is proportional to collision velocity
|
||||||
// Base frequency is modified upward by the angle of the collision
|
// Base frequency is modified upward by the angle of the collision
|
||||||
|
|
|
@ -19,11 +19,14 @@
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
#include <UUID.h>
|
#include <UUID.h>
|
||||||
#include <VoxelConstants.h>
|
#include <VoxelConstants.h>
|
||||||
|
#include <ParticlesScriptingInterface.h>
|
||||||
|
|
||||||
#include <Sound.h>
|
#include <Sound.h>
|
||||||
|
|
||||||
#include "ScriptEngine.h"
|
#include "ScriptEngine.h"
|
||||||
|
|
||||||
|
const unsigned int VISUAL_DATA_CALLBACK_USECS = (1.0 / 60.0) * 1000 * 1000;
|
||||||
|
|
||||||
int ScriptEngine::_scriptNumber = 1;
|
int ScriptEngine::_scriptNumber = 1;
|
||||||
VoxelsScriptingInterface ScriptEngine::_voxelsScriptingInterface;
|
VoxelsScriptingInterface ScriptEngine::_voxelsScriptingInterface;
|
||||||
ParticlesScriptingInterface ScriptEngine::_particlesScriptingInterface;
|
ParticlesScriptingInterface ScriptEngine::_particlesScriptingInterface;
|
||||||
|
@ -31,7 +34,7 @@ ParticlesScriptingInterface ScriptEngine::_particlesScriptingInterface;
|
||||||
static QScriptValue soundConstructor(QScriptContext* context, QScriptEngine* engine) {
|
static QScriptValue soundConstructor(QScriptContext* context, QScriptEngine* engine) {
|
||||||
QUrl soundURL = QUrl(context->argument(0).toString());
|
QUrl soundURL = QUrl(context->argument(0).toString());
|
||||||
QScriptValue soundScriptValue = engine->newQObject(new Sound(soundURL), QScriptEngine::ScriptOwnership);
|
QScriptValue soundScriptValue = engine->newQObject(new Sound(soundURL), QScriptEngine::ScriptOwnership);
|
||||||
|
|
||||||
return soundScriptValue;
|
return soundScriptValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +44,8 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems,
|
||||||
_scriptContents = scriptContents;
|
_scriptContents = scriptContents;
|
||||||
_isFinished = false;
|
_isFinished = false;
|
||||||
_isRunning = false;
|
_isRunning = false;
|
||||||
|
_isInitialized = false;
|
||||||
|
|
||||||
// some clients will use these menu features
|
// some clients will use these menu features
|
||||||
_wantMenuItems = wantMenuItems;
|
_wantMenuItems = wantMenuItems;
|
||||||
if (scriptMenuName) {
|
if (scriptMenuName) {
|
||||||
|
@ -54,15 +58,6 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems,
|
||||||
}
|
}
|
||||||
_menu = menu;
|
_menu = menu;
|
||||||
_controllerScriptingInterface = controllerScriptingInterface;
|
_controllerScriptingInterface = controllerScriptingInterface;
|
||||||
|
|
||||||
// hook up our interfaces
|
|
||||||
if (!Particle::getVoxelsScriptingInterface()) {
|
|
||||||
Particle::setVoxelsScriptingInterface(getVoxelsScriptingInterface());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Particle::getParticlesScriptingInterface()) {
|
|
||||||
Particle::setParticlesScriptingInterface(getParticlesScriptingInterface());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptEngine::~ScriptEngine() {
|
ScriptEngine::~ScriptEngine() {
|
||||||
|
@ -92,63 +87,89 @@ bool ScriptEngine::setScriptContents(const QString& scriptContents) {
|
||||||
|
|
||||||
Q_SCRIPT_DECLARE_QMETAOBJECT(AudioInjectorOptions, QObject*)
|
Q_SCRIPT_DECLARE_QMETAOBJECT(AudioInjectorOptions, QObject*)
|
||||||
|
|
||||||
void ScriptEngine::run() {
|
void ScriptEngine::init() {
|
||||||
_isRunning = true;
|
if (_isInitialized) {
|
||||||
QScriptEngine engine;
|
return; // only initialize once
|
||||||
|
}
|
||||||
|
|
||||||
|
_isInitialized = true;
|
||||||
|
|
||||||
_voxelsScriptingInterface.init();
|
_voxelsScriptingInterface.init();
|
||||||
_particlesScriptingInterface.init();
|
_particlesScriptingInterface.init();
|
||||||
|
|
||||||
// register meta-type for glm::vec3 conversions
|
|
||||||
registerMetaTypes(&engine);
|
|
||||||
|
|
||||||
QScriptValue agentValue = engine.newQObject(this);
|
|
||||||
engine.globalObject().setProperty("Agent", agentValue);
|
|
||||||
|
|
||||||
QScriptValue voxelScripterValue = engine.newQObject(&_voxelsScriptingInterface);
|
|
||||||
engine.globalObject().setProperty("Voxels", voxelScripterValue);
|
|
||||||
|
|
||||||
QScriptValue particleScripterValue = engine.newQObject(&_particlesScriptingInterface);
|
// register meta-type for glm::vec3 conversions
|
||||||
engine.globalObject().setProperty("Particles", particleScripterValue);
|
registerMetaTypes(&_engine);
|
||||||
|
|
||||||
|
QScriptValue agentValue = _engine.newQObject(this);
|
||||||
QScriptValue soundConstructorValue = engine.newFunction(soundConstructor);
|
_engine.globalObject().setProperty("Agent", agentValue);
|
||||||
QScriptValue soundMetaObject = engine.newQMetaObject(&Sound::staticMetaObject, soundConstructorValue);
|
|
||||||
engine.globalObject().setProperty("Sound", soundMetaObject);
|
QScriptValue voxelScripterValue = _engine.newQObject(&_voxelsScriptingInterface);
|
||||||
|
_engine.globalObject().setProperty("Voxels", voxelScripterValue);
|
||||||
QScriptValue injectionOptionValue = engine.scriptValueFromQMetaObject<AudioInjectorOptions>();
|
|
||||||
engine.globalObject().setProperty("AudioInjectionOptions", injectionOptionValue);
|
QScriptValue particleScripterValue = _engine.newQObject(&_particlesScriptingInterface);
|
||||||
|
_engine.globalObject().setProperty("Particles", particleScripterValue);
|
||||||
QScriptValue audioScriptingInterfaceValue = engine.newQObject(&_audioScriptingInterface);
|
|
||||||
engine.globalObject().setProperty("Audio", audioScriptingInterfaceValue);
|
QScriptValue soundConstructorValue = _engine.newFunction(soundConstructor);
|
||||||
|
QScriptValue soundMetaObject = _engine.newQMetaObject(&Sound::staticMetaObject, soundConstructorValue);
|
||||||
|
_engine.globalObject().setProperty("Sound", soundMetaObject);
|
||||||
|
|
||||||
|
QScriptValue injectionOptionValue = _engine.scriptValueFromQMetaObject<AudioInjectorOptions>();
|
||||||
|
_engine.globalObject().setProperty("AudioInjectionOptions", injectionOptionValue);
|
||||||
|
|
||||||
|
QScriptValue audioScriptingInterfaceValue = _engine.newQObject(&_audioScriptingInterface);
|
||||||
|
_engine.globalObject().setProperty("Audio", audioScriptingInterfaceValue);
|
||||||
|
|
||||||
if (_controllerScriptingInterface) {
|
if (_controllerScriptingInterface) {
|
||||||
QScriptValue controllerScripterValue = engine.newQObject(_controllerScriptingInterface);
|
QScriptValue controllerScripterValue = _engine.newQObject(_controllerScriptingInterface);
|
||||||
engine.globalObject().setProperty("Controller", controllerScripterValue);
|
_engine.globalObject().setProperty("Controller", controllerScripterValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE));
|
QScriptValue treeScaleValue = _engine.newVariant(QVariant(TREE_SCALE));
|
||||||
engine.globalObject().setProperty("TREE_SCALE", treeScaleValue);
|
_engine.globalObject().setProperty("TREE_SCALE", treeScaleValue);
|
||||||
|
|
||||||
const unsigned int VISUAL_DATA_CALLBACK_USECS = (1.0 / 60.0) * 1000 * 1000;
|
|
||||||
|
|
||||||
// let the VoxelPacketSender know how frequently we plan to call it
|
// let the VoxelPacketSender know how frequently we plan to call it
|
||||||
_voxelsScriptingInterface.getVoxelPacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS);
|
_voxelsScriptingInterface.getVoxelPacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS);
|
||||||
_particlesScriptingInterface.getParticlePacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS);
|
_particlesScriptingInterface.getParticlePacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS);
|
||||||
|
|
||||||
//qDebug() << "Script:\n" << _scriptContents << "\n";
|
//qDebug() << "Script:\n" << _scriptContents << "\n";
|
||||||
|
}
|
||||||
QScriptValue result = engine.evaluate(_scriptContents);
|
|
||||||
|
void ScriptEngine::registerGlobalObject(const QString& name, QObject* object) {
|
||||||
|
QScriptValue value = _engine.newQObject(object);
|
||||||
|
_engine.globalObject().setProperty(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::evaluate() {
|
||||||
|
if (!_isInitialized) {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QScriptValue result = _engine.evaluate(_scriptContents);
|
||||||
qDebug() << "Evaluated script.\n";
|
qDebug() << "Evaluated script.\n";
|
||||||
|
|
||||||
if (engine.hasUncaughtException()) {
|
if (_engine.hasUncaughtException()) {
|
||||||
int line = engine.uncaughtExceptionLineNumber();
|
int line = _engine.uncaughtExceptionLineNumber();
|
||||||
qDebug() << "Uncaught exception at line" << line << ":" << result.toString() << "\n";
|
qDebug() << "Uncaught exception at line" << line << ":" << result.toString() << "\n";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::run() {
|
||||||
|
if (!_isInitialized) {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
_isRunning = true;
|
||||||
|
|
||||||
|
QScriptValue result = _engine.evaluate(_scriptContents);
|
||||||
|
qDebug() << "Evaluated script.\n";
|
||||||
|
|
||||||
|
if (_engine.hasUncaughtException()) {
|
||||||
|
int line = _engine.uncaughtExceptionLineNumber();
|
||||||
|
qDebug() << "Uncaught exception at line" << line << ":" << result.toString() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
timeval startTime;
|
timeval startTime;
|
||||||
gettimeofday(&startTime, NULL);
|
gettimeofday(&startTime, NULL);
|
||||||
|
|
||||||
int thisFrame = 0;
|
int thisFrame = 0;
|
||||||
|
|
||||||
while (!_isFinished) {
|
while (!_isFinished) {
|
||||||
|
@ -166,15 +187,15 @@ void ScriptEngine::run() {
|
||||||
if (_isFinished) {
|
if (_isFinished) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool willSendVisualDataCallBack = false;
|
bool willSendVisualDataCallBack = false;
|
||||||
if (_voxelsScriptingInterface.getVoxelPacketSender()->serversExist()) {
|
if (_voxelsScriptingInterface.getVoxelPacketSender()->serversExist()) {
|
||||||
// allow the scripter's call back to setup visual data
|
// allow the scripter's call back to setup visual data
|
||||||
willSendVisualDataCallBack = true;
|
willSendVisualDataCallBack = true;
|
||||||
|
|
||||||
// release the queue of edit voxel messages.
|
// release the queue of edit voxel messages.
|
||||||
_voxelsScriptingInterface.getVoxelPacketSender()->releaseQueuedMessages();
|
_voxelsScriptingInterface.getVoxelPacketSender()->releaseQueuedMessages();
|
||||||
|
|
||||||
// since we're in non-threaded mode, call process so that the packets are sent
|
// since we're in non-threaded mode, call process so that the packets are sent
|
||||||
if (!_voxelsScriptingInterface.getVoxelPacketSender()->isThreaded()) {
|
if (!_voxelsScriptingInterface.getVoxelPacketSender()->isThreaded()) {
|
||||||
_voxelsScriptingInterface.getVoxelPacketSender()->process();
|
_voxelsScriptingInterface.getVoxelPacketSender()->process();
|
||||||
|
@ -184,23 +205,23 @@ void ScriptEngine::run() {
|
||||||
if (_particlesScriptingInterface.getParticlePacketSender()->serversExist()) {
|
if (_particlesScriptingInterface.getParticlePacketSender()->serversExist()) {
|
||||||
// allow the scripter's call back to setup visual data
|
// allow the scripter's call back to setup visual data
|
||||||
willSendVisualDataCallBack = true;
|
willSendVisualDataCallBack = true;
|
||||||
|
|
||||||
// release the queue of edit voxel messages.
|
// release the queue of edit voxel messages.
|
||||||
_particlesScriptingInterface.getParticlePacketSender()->releaseQueuedMessages();
|
_particlesScriptingInterface.getParticlePacketSender()->releaseQueuedMessages();
|
||||||
|
|
||||||
// since we're in non-threaded mode, call process so that the packets are sent
|
// since we're in non-threaded mode, call process so that the packets are sent
|
||||||
if (!_particlesScriptingInterface.getParticlePacketSender()->isThreaded()) {
|
if (!_particlesScriptingInterface.getParticlePacketSender()->isThreaded()) {
|
||||||
_particlesScriptingInterface.getParticlePacketSender()->process();
|
_particlesScriptingInterface.getParticlePacketSender()->process();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (willSendVisualDataCallBack) {
|
if (willSendVisualDataCallBack) {
|
||||||
emit willSendVisualDataCallback();
|
emit willSendVisualDataCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (engine.hasUncaughtException()) {
|
if (_engine.hasUncaughtException()) {
|
||||||
int line = engine.uncaughtExceptionLineNumber();
|
int line = _engine.uncaughtExceptionLineNumber();
|
||||||
qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n";
|
qDebug() << "Uncaught exception at line" << line << ":" << _engine.uncaughtException().toString() << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cleanMenuItems();
|
cleanMenuItems();
|
||||||
|
@ -213,9 +234,8 @@ void ScriptEngine::run() {
|
||||||
emit finished();
|
emit finished();
|
||||||
_isRunning = false;
|
_isRunning = false;
|
||||||
}
|
}
|
||||||
|
void ScriptEngine::stop() {
|
||||||
void ScriptEngine::stop() {
|
_isFinished = true;
|
||||||
_isFinished = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,10 @@
|
||||||
|
|
||||||
#include <AbstractMenuInterface.h>
|
#include <AbstractMenuInterface.h>
|
||||||
#include <AudioScriptingInterface.h>
|
#include <AudioScriptingInterface.h>
|
||||||
#include <ParticlesScriptingInterface.h>
|
|
||||||
#include <VoxelsScriptingInterface.h>
|
#include <VoxelsScriptingInterface.h>
|
||||||
|
|
||||||
|
class ParticlesScriptingInterface;
|
||||||
|
|
||||||
#include "AbstractControllerScriptingInterface.h"
|
#include "AbstractControllerScriptingInterface.h"
|
||||||
|
|
||||||
const QString NO_SCRIPT("");
|
const QString NO_SCRIPT("");
|
||||||
|
@ -27,12 +28,12 @@ const QString NO_SCRIPT("");
|
||||||
class ScriptEngine : public QObject {
|
class ScriptEngine : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
ScriptEngine(const QString& scriptContents = NO_SCRIPT, bool wantMenuItems = false,
|
ScriptEngine(const QString& scriptContents = NO_SCRIPT, bool wantMenuItems = false,
|
||||||
const char* scriptMenuName = NULL, AbstractMenuInterface* menu = NULL,
|
const char* scriptMenuName = NULL, AbstractMenuInterface* menu = NULL,
|
||||||
AbstractControllerScriptingInterface* controllerScriptingInterface = NULL);
|
AbstractControllerScriptingInterface* controllerScriptingInterface = NULL);
|
||||||
|
|
||||||
~ScriptEngine();
|
~ScriptEngine();
|
||||||
|
|
||||||
/// Access the VoxelsScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener
|
/// Access the VoxelsScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener
|
||||||
VoxelsScriptingInterface* getVoxelsScriptingInterface() { return &_voxelsScriptingInterface; }
|
VoxelsScriptingInterface* getVoxelsScriptingInterface() { return &_voxelsScriptingInterface; }
|
||||||
|
|
||||||
|
@ -44,11 +45,15 @@ public:
|
||||||
|
|
||||||
void setupMenuItems();
|
void setupMenuItems();
|
||||||
void cleanMenuItems();
|
void cleanMenuItems();
|
||||||
|
|
||||||
|
void registerGlobalObject(const QString& name, QObject* object); /// registers a global object by name
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void run();
|
void init();
|
||||||
|
void run(); /// runs continuously until Agent.stop() is called
|
||||||
void stop();
|
void stop();
|
||||||
|
void evaluate(); /// initializes the engine, and evaluates the script, but then returns control to caller
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void willSendAudioDataCallback();
|
void willSendAudioDataCallback();
|
||||||
void willSendVisualDataCallback();
|
void willSendVisualDataCallback();
|
||||||
|
@ -57,7 +62,8 @@ protected:
|
||||||
QString _scriptContents;
|
QString _scriptContents;
|
||||||
bool _isFinished;
|
bool _isFinished;
|
||||||
bool _isRunning;
|
bool _isRunning;
|
||||||
|
bool _isInitialized;
|
||||||
|
QScriptEngine _engine;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static VoxelsScriptingInterface _voxelsScriptingInterface;
|
static VoxelsScriptingInterface _voxelsScriptingInterface;
|
||||||
|
|
Loading…
Reference in a new issue