示例#1
0
void ScriptEngine::run() {
    if (!_isInitialized) {
        init();
    }
    _isRunning = true;
    emit runningStateChanged();

    QScriptValue result = _engine.evaluate(_scriptContents);
    if (_engine.hasUncaughtException()) {
        int line = _engine.uncaughtExceptionLineNumber();

        qDebug() << "Uncaught exception at line" << line << ":" << result.toString();
        emit errorMessage("Uncaught exception at line" + QString::number(line) + ":" + result.toString());
    }

    QElapsedTimer startTime;
    startTime.start();

    int thisFrame = 0;

    NodeList* nodeList = NodeList::getInstance();

    qint64 lastUpdate = usecTimestampNow();

    while (!_isFinished) {
        int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec
        if (usecToSleep > 0) {
            usleep(usecToSleep);
        }

        if (_isFinished) {
            break;
        }

        QCoreApplication::processEvents();

        if (_isFinished) {
            break;
        }

        if (_voxelsScriptingInterface.getVoxelPacketSender()->serversExist()) {
            // release the queue of edit voxel messages.
            _voxelsScriptingInterface.getVoxelPacketSender()->releaseQueuedMessages();

            // since we're in non-threaded mode, call process so that the packets are sent
            if (!_voxelsScriptingInterface.getVoxelPacketSender()->isThreaded()) {
                _voxelsScriptingInterface.getVoxelPacketSender()->process();
            }
        }

        if (_particlesScriptingInterface.getParticlePacketSender()->serversExist()) {
            // release the queue of edit voxel messages.
            _particlesScriptingInterface.getParticlePacketSender()->releaseQueuedMessages();

            // since we're in non-threaded mode, call process so that the packets are sent
            if (!_particlesScriptingInterface.getParticlePacketSender()->isThreaded()) {
                _particlesScriptingInterface.getParticlePacketSender()->process();
            }
        }

        if (_modelsScriptingInterface.getModelPacketSender()->serversExist()) {
            // release the queue of edit voxel messages.
            _modelsScriptingInterface.getModelPacketSender()->releaseQueuedMessages();

            // since we're in non-threaded mode, call process so that the packets are sent
            if (!_modelsScriptingInterface.getModelPacketSender()->isThreaded()) {
                _modelsScriptingInterface.getModelPacketSender()->process();
            }
        }

        if (_isAvatar && _avatarData) {

            const int SCRIPT_AUDIO_BUFFER_SAMPLES = floor(((SCRIPT_DATA_CALLBACK_USECS * SAMPLE_RATE) / (1000 * 1000)) + 0.5);
            const int SCRIPT_AUDIO_BUFFER_BYTES = SCRIPT_AUDIO_BUFFER_SAMPLES * sizeof(int16_t);

            QByteArray avatarPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarData);
            avatarPacket.append(_avatarData->toByteArray());

            nodeList->broadcastToNodes(avatarPacket, NodeSet() << NodeType::AvatarMixer);

            if (_isListeningToAudioStream || _avatarSound) {
                // if we have an avatar audio stream then send it out to our audio-mixer
                bool silentFrame = true;

                int16_t numAvailableSamples = SCRIPT_AUDIO_BUFFER_SAMPLES;
                const int16_t* nextSoundOutput = NULL;

                if (_avatarSound) {

                    const QByteArray& soundByteArray = _avatarSound->getByteArray();
                    nextSoundOutput = reinterpret_cast<const int16_t*>(soundByteArray.data()
                                                                       + _numAvatarSoundSentBytes);

                    int numAvailableBytes = (soundByteArray.size() - _numAvatarSoundSentBytes) > SCRIPT_AUDIO_BUFFER_BYTES
                        ? SCRIPT_AUDIO_BUFFER_BYTES
                        : soundByteArray.size() - _numAvatarSoundSentBytes;
                    numAvailableSamples = numAvailableBytes / sizeof(int16_t);


                    // check if the all of the _numAvatarAudioBufferSamples to be sent are silence
                    for (int i = 0; i < numAvailableSamples; ++i) {
                        if (nextSoundOutput[i] != 0) {
                            silentFrame = false;
                            break;
                        }
                    }

                    _numAvatarSoundSentBytes += numAvailableBytes;
                    if (_numAvatarSoundSentBytes == soundByteArray.size()) {
                        // we're done with this sound object - so set our pointer back to NULL
                        // and our sent bytes back to zero
                        _avatarSound = NULL;
                        _numAvatarSoundSentBytes = 0;
                    }
                }

                QByteArray audioPacket = byteArrayWithPopulatedHeader(silentFrame
                                                                      ? PacketTypeSilentAudioFrame
                                                                      : PacketTypeMicrophoneAudioNoEcho);

                QDataStream packetStream(&audioPacket, QIODevice::Append);

                // use the orientation and position of this avatar for the source of this audio
                packetStream.writeRawData(reinterpret_cast<const char*>(&_avatarData->getPosition()), sizeof(glm::vec3));
                glm::quat headOrientation = _avatarData->getHeadOrientation();
                packetStream.writeRawData(reinterpret_cast<const char*>(&headOrientation), sizeof(glm::quat));

                if (silentFrame) {
                    if (!_isListeningToAudioStream) {
                        // if we have a silent frame and we're not listening then just send nothing and break out of here
                        break;
                    }

                    // write the number of silent samples so the audio-mixer can uphold timing
                    packetStream.writeRawData(reinterpret_cast<const char*>(&SCRIPT_AUDIO_BUFFER_SAMPLES), sizeof(int16_t));
                } else if (nextSoundOutput) {
                    // write the raw audio data
                    packetStream.writeRawData(reinterpret_cast<const char*>(nextSoundOutput),
                                              numAvailableSamples * sizeof(int16_t));
                }

                nodeList->broadcastToNodes(audioPacket, NodeSet() << NodeType::AudioMixer);
            }
        }

        qint64 now = usecTimestampNow();
        float deltaTime = (float) (now - lastUpdate) / (float) USECS_PER_SECOND;
        emit update(deltaTime);
        lastUpdate = now;

        if (_engine.hasUncaughtException()) {
            int line = _engine.uncaughtExceptionLineNumber();
            qDebug() << "Uncaught exception at line" << line << ":" << _engine.uncaughtException().toString();
            emit errorMessage("Uncaught exception at line" + QString::number(line) + ":" + _engine.uncaughtException().toString());
        }
    }
    emit scriptEnding();

    // kill the avatar identity timer
    delete _avatarIdentityTimer;

    if (_voxelsScriptingInterface.getVoxelPacketSender()->serversExist()) {
        // release the queue of edit voxel messages.
        _voxelsScriptingInterface.getVoxelPacketSender()->releaseQueuedMessages();

        // since we're in non-threaded mode, call process so that the packets are sent
        if (!_voxelsScriptingInterface.getVoxelPacketSender()->isThreaded()) {
            _voxelsScriptingInterface.getVoxelPacketSender()->process();
        }
    }

    if (_particlesScriptingInterface.getParticlePacketSender()->serversExist()) {
        // release the queue of edit voxel messages.
        _particlesScriptingInterface.getParticlePacketSender()->releaseQueuedMessages();

        // since we're in non-threaded mode, call process so that the packets are sent
        if (!_particlesScriptingInterface.getParticlePacketSender()->isThreaded()) {
            _particlesScriptingInterface.getParticlePacketSender()->process();
        }
    }

    if (_modelsScriptingInterface.getModelPacketSender()->serversExist()) {
        // release the queue of edit voxel messages.
        _modelsScriptingInterface.getModelPacketSender()->releaseQueuedMessages();

        // since we're in non-threaded mode, call process so that the packets are sent
        if (!_modelsScriptingInterface.getModelPacketSender()->isThreaded()) {
            _modelsScriptingInterface.getModelPacketSender()->process();
        }
    }

    // If we were on a thread, then wait till it's done
    if (thread()) {
        thread()->quit();
    }

    emit finished(_fileNameString);

    _isRunning = false;
    emit runningStateChanged();
}
示例#2
0
文件: main.cpp 项目: evilbinary/hifi
int main(int argc, const char * argv[]) {
    pthread_mutex_init(&::treeLock, NULL);
    
    qInstallMessageHandler(sharedMessageHandler);
    
    NodeList* nodeList = NodeList::createInstance(NODE_TYPE_VOXEL_SERVER, VOXEL_LISTEN_PORT);
    setvbuf(stdout, NULL, _IOLBF, 0);

    // Handle Local Domain testing with the --local command line
    const char* local = "--local";
    ::wantLocalDomain = cmdOptionExists(argc, argv,local);
    if (::wantLocalDomain) {
        printf("Local Domain MODE!\n");
        nodeList->setDomainIPToLocalhost();
    }

    nodeList->linkedDataCreateCallback = &attachVoxelNodeDataToNode;
    nodeList->startSilentNodeRemovalThread();
    
    srand((unsigned)time(0));
    
    const char* DISPLAY_VOXEL_STATS = "--displayVoxelStats";
    ::displayVoxelStats = cmdOptionExists(argc, argv, DISPLAY_VOXEL_STATS);
    printf("displayVoxelStats=%s\n", debug::valueOf(::displayVoxelStats));

    const char* DEBUG_VOXEL_SENDING = "--debugVoxelSending";
    ::debugVoxelSending = cmdOptionExists(argc, argv, DEBUG_VOXEL_SENDING);
    printf("debugVoxelSending=%s\n", debug::valueOf(::debugVoxelSending));

    const char* DEBUG_VOXEL_RECEIVING = "--debugVoxelReceiving";
    ::debugVoxelReceiving = cmdOptionExists(argc, argv, DEBUG_VOXEL_RECEIVING);
    printf("debugVoxelReceiving=%s\n", debug::valueOf(::debugVoxelReceiving));

    const char* WANT_ANIMATION_DEBUG = "--shouldShowAnimationDebug";
    ::shouldShowAnimationDebug = cmdOptionExists(argc, argv, WANT_ANIMATION_DEBUG);
    printf("shouldShowAnimationDebug=%s\n", debug::valueOf(::shouldShowAnimationDebug));

    const char* WANT_COLOR_RANDOMIZER = "--wantColorRandomizer";
    ::wantColorRandomizer = cmdOptionExists(argc, argv, WANT_COLOR_RANDOMIZER);
    printf("wantColorRandomizer=%s\n", debug::valueOf(::wantColorRandomizer));

    // By default we will voxel persist, if you want to disable this, then pass in this parameter
    const char* NO_VOXEL_PERSIST = "--NoVoxelPersist";
    if (cmdOptionExists(argc, argv, NO_VOXEL_PERSIST)) {
        ::wantVoxelPersist = false;
    }
    printf("wantVoxelPersist=%s\n", debug::valueOf(::wantVoxelPersist));

    // if we want Voxel Persistance, load the local file now...
    bool persistantFileRead = false;
    if (::wantVoxelPersist) {
        printf("loading voxels from file...\n");
        persistantFileRead = ::serverTree.readFromSVOFile(::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE);
        if (persistantFileRead) {
            PerformanceWarning warn(::shouldShowAnimationDebug,
                                    "persistVoxelsWhenDirty() - reaverageVoxelColors()", ::shouldShowAnimationDebug);
            
            // after done inserting all these voxels, then reaverage colors
            serverTree.reaverageVoxelColors(serverTree.rootNode);
            printf("Voxels reAveraged\n");
        }
        
        ::serverTree.clearDirtyBit(); // the tree is clean since we just loaded it
        printf("DONE loading voxels from file... fileRead=%s\n", debug::valueOf(persistantFileRead));
        unsigned long nodeCount         = ::serverTree.rootNode->getSubTreeNodeCount();
        unsigned long internalNodeCount = ::serverTree.rootNode->getSubTreeInternalNodeCount();
        unsigned long leafNodeCount     = ::serverTree.rootNode->getSubTreeLeafNodeCount();
        printf("Nodes after loading scene %lu nodes %lu internal %lu leaves\n", nodeCount, internalNodeCount, leafNodeCount);
    }

    // Check to see if the user passed in a command line option for loading an old style local
    // Voxel File. If so, load it now. This is not the same as a voxel persist file
    const char* INPUT_FILE = "-i";
    const char* voxelsFilename = getCmdOption(argc, argv, INPUT_FILE);
    if (voxelsFilename) {
        serverTree.readFromSVOFile(voxelsFilename);
    }

    // Check to see if the user passed in a command line option for setting packet send rate
    const char* PACKETS_PER_SECOND = "--packetsPerSecond";
    const char* packetsPerSecond = getCmdOption(argc, argv, PACKETS_PER_SECOND);
    if (packetsPerSecond) {
        PACKETS_PER_CLIENT_PER_INTERVAL = atoi(packetsPerSecond)/10;
        if (PACKETS_PER_CLIENT_PER_INTERVAL < 1) {
            PACKETS_PER_CLIENT_PER_INTERVAL = 1;
        }
        printf("packetsPerSecond=%s PACKETS_PER_CLIENT_PER_INTERVAL=%d\n", packetsPerSecond, PACKETS_PER_CLIENT_PER_INTERVAL);
    }
    
    const char* ADD_RANDOM_VOXELS = "--AddRandomVoxels";
    if (cmdOptionExists(argc, argv, ADD_RANDOM_VOXELS)) {
        // create an octal code buffer and load it with 0 so that the recursive tree fill can give
        // octal codes to the tree nodes that it is creating
        randomlyFillVoxelTree(MAX_VOXEL_TREE_DEPTH_LEVELS, serverTree.rootNode);
    }

    const char* ADD_SCENE = "--AddScene";
    bool addScene = cmdOptionExists(argc, argv, ADD_SCENE);
    const char* NO_ADD_SCENE = "--NoAddScene";
    bool noAddScene = cmdOptionExists(argc, argv, NO_ADD_SCENE);
    if (addScene && noAddScene) {
        printf("WARNING! --AddScene and --NoAddScene are mutually exclusive. We will honor --NoAddScene\n");
    }

    // We will add a scene if...
    //      1) we attempted to load a persistant file and it wasn't there
    //      2) you asked us to add a scene
    // HOWEVER -- we will NEVER add a scene if you explicitly tell us not to!
    //
    // TEMPORARILY DISABLED!!!
    bool actuallyAddScene = false; // !noAddScene && (addScene || (::wantVoxelPersist && !persistantFileRead));
    if (actuallyAddScene) {
        addSphereScene(&serverTree);
    }
    
    // for now, initialize the environments with fixed values
    environmentData[1].setID(1);
    environmentData[1].setGravity(1.0f);
    environmentData[1].setAtmosphereCenter(glm::vec3(0.5, 0.5, (0.25 - 0.06125)) * (float)TREE_SCALE);
    environmentData[1].setAtmosphereInnerRadius(0.030625f * TREE_SCALE);
    environmentData[1].setAtmosphereOuterRadius(0.030625f * TREE_SCALE * 1.05f);
    environmentData[2].setID(2);
    environmentData[2].setGravity(1.0f);
    environmentData[2].setAtmosphereCenter(glm::vec3(0.5f, 0.5f, 0.5f) * (float)TREE_SCALE);
    environmentData[2].setAtmosphereInnerRadius(0.1875f * TREE_SCALE);
    environmentData[2].setAtmosphereOuterRadius(0.1875f * TREE_SCALE * 1.05f);
    environmentData[2].setScatteringWavelengths(glm::vec3(0.475f, 0.570f, 0.650f)); // swaps red and blue
    
    pthread_t sendVoxelThread;
    pthread_create(&sendVoxelThread, NULL, distributeVoxelsToListeners, NULL);

    sockaddr nodePublicAddress;
    
    unsigned char *packetData = new unsigned char[MAX_PACKET_SIZE];
    ssize_t receivedBytes;
    
    timeval lastDomainServerCheckIn = {};

    // loop to send to nodes requesting data
    
    while (true) {

        // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed
        if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) {
            gettimeofday(&lastDomainServerCheckIn, NULL);
            NodeList::getInstance()->sendDomainServerCheckIn();
        }
        
        // check to see if we need to persist our voxel state
        persistVoxelsWhenDirty();
    
        if (nodeList->getNodeSocket()->receive(&nodePublicAddress, packetData, &receivedBytes) &&
            packetVersionMatch(packetData)) {
            
            int numBytesPacketHeader = numBytesForPacketHeader(packetData);
            
            if (packetData[0] == PACKET_TYPE_SET_VOXEL || packetData[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE) {
                bool destructive = (packetData[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE);
                PerformanceWarning warn(::shouldShowAnimationDebug,
                                        destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL",
                                        ::shouldShowAnimationDebug);
                
                ::receivedPacketCount++;
                
                unsigned short int itemNumber = (*((unsigned short int*)(packetData + numBytesPacketHeader)));
                if (::shouldShowAnimationDebug) {
                    printf("got %s - command from client receivedBytes=%ld itemNumber=%d\n",
                        destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL",
                        receivedBytes,itemNumber);
                }
                
                if (::debugVoxelReceiving) {
                    printf("got %s - %d command from client receivedBytes=%ld itemNumber=%d\n",
                        destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL",
                        ::receivedPacketCount, receivedBytes,itemNumber);
                }
                int atByte = numBytesPacketHeader + sizeof(itemNumber);
                unsigned char* voxelData = (unsigned char*)&packetData[atByte];
                while (atByte < receivedBytes) {
                    unsigned char octets = (unsigned char)*voxelData;
                    const int COLOR_SIZE_IN_BYTES = 3;
                    int voxelDataSize = bytesRequiredForCodeLength(octets) + COLOR_SIZE_IN_BYTES;
                    int voxelCodeSize = bytesRequiredForCodeLength(octets);

                    // color randomization on insert
                    int colorRandomizer = ::wantColorRandomizer ? randIntInRange (-50, 50) : 0;
                    int red   = voxelData[voxelCodeSize + 0];
                    int green = voxelData[voxelCodeSize + 1];
                    int blue  = voxelData[voxelCodeSize + 2];

                    if (::shouldShowAnimationDebug) {
                        printf("insert voxels - wantColorRandomizer=%s old r=%d,g=%d,b=%d \n",
                            (::wantColorRandomizer?"yes":"no"),red,green,blue);
                    }
                
                    red   = std::max(0, std::min(255, red   + colorRandomizer));
                    green = std::max(0, std::min(255, green + colorRandomizer));
                    blue  = std::max(0, std::min(255, blue  + colorRandomizer));

                    if (::shouldShowAnimationDebug) {
                        printf("insert voxels - wantColorRandomizer=%s NEW r=%d,g=%d,b=%d \n",
                            (::wantColorRandomizer?"yes":"no"),red,green,blue);
                    }
                    voxelData[voxelCodeSize + 0] = red;
                    voxelData[voxelCodeSize + 1] = green;
                    voxelData[voxelCodeSize + 2] = blue;

                    if (::shouldShowAnimationDebug) {
                        float* vertices = firstVertexForCode(voxelData);
                        printf("inserting voxel at: %f,%f,%f\n", vertices[0], vertices[1], vertices[2]);
                        delete []vertices;
                    }
                
                    serverTree.readCodeColorBufferToTree(voxelData, destructive);
                    // skip to next
                    voxelData += voxelDataSize;
                    atByte += voxelDataSize;
                }
            } else if (packetData[0] == PACKET_TYPE_ERASE_VOXEL) {

                // Send these bits off to the VoxelTree class to process them
                pthread_mutex_lock(&::treeLock);
                serverTree.processRemoveVoxelBitstream((unsigned char*)packetData, receivedBytes);
                pthread_mutex_unlock(&::treeLock);
            } else if (packetData[0] == PACKET_TYPE_Z_COMMAND) {

                // the Z command is a special command that allows the sender to send the voxel server high level semantic
                // requests, like erase all, or add sphere scene
                
                char* command = (char*) &packetData[numBytesPacketHeader]; // start of the command
                int commandLength = strlen(command); // commands are null terminated strings
                int totalLength = numBytesPacketHeader + commandLength + 1; // 1 for null termination
                printf("got Z message len(%ld)= %s\n", receivedBytes, command);
                bool rebroadcast = true; // by default rebroadcast

                while (totalLength <= receivedBytes) {
                    if (strcmp(command, ERASE_ALL_COMMAND) == 0) {
                        printf("got Z message == erase all\n");
                        eraseVoxelTreeAndCleanupNodeVisitData();
                        rebroadcast = false;
                    }
                    if (strcmp(command, ADD_SCENE_COMMAND) == 0) {
                        printf("got Z message == add scene\n");
                        addSphereScene(&serverTree);
                        rebroadcast = false;
                    }
                    if (strcmp(command, TEST_COMMAND) == 0) {
                        printf("got Z message == a message, nothing to do, just report\n");
                    }
                    totalLength += commandLength + 1; // 1 for null termination
                }

                if (rebroadcast) {
                    // Now send this to the connected nodes so they can also process these messages
                    printf("rebroadcasting Z message to connected nodes... nodeList.broadcastToNodes()\n");
                    nodeList->broadcastToNodes(packetData, receivedBytes, &NODE_TYPE_AGENT, 1);
                }
            } else if (packetData[0] == PACKET_TYPE_HEAD_DATA) {
                // If we got a PACKET_TYPE_HEAD_DATA, then we're talking to an NODE_TYPE_AVATAR, and we
                // need to make sure we have it in our nodeList.
                
                uint16_t nodeID = 0;
                unpackNodeId(packetData + numBytesPacketHeader, &nodeID);
                Node* node = nodeList->addOrUpdateNode(&nodePublicAddress,
                                                       &nodePublicAddress,
                                                       NODE_TYPE_AGENT,
                                                       nodeID);
                
                nodeList->updateNodeWithData(node, packetData, receivedBytes);
            } else if (packetData[0] == PACKET_TYPE_PING) {
                // If the packet is a ping, let processNodeData handle it.
                nodeList->processNodeData(&nodePublicAddress, packetData, receivedBytes);
            }
        }
    }
    
    pthread_join(sendVoxelThread, NULL);
    pthread_mutex_destroy(&::treeLock);

    return 0;
}