1214 lines · 40.8 KB · C++
RawDownload
////  SharedUtil.cpp//  libraries/shared/src////  Created by Stephen Birarda on 2/22/13.//  Copyright 2013 High Fidelity, Inc.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include "SharedUtil.h" #include <cassert>#include <cstdlib>#include <cstdio>#include <cstring>#include <cctype>#include <time.h>#include <mutex>#include <thread>#include <unordered_map>#include <chrono> #include <QtCore/QOperatingSystemVersion>#include <glm/glm.hpp> #ifdef Q_OS_WIN#include <windows.h>#include "CPUIdent.h"#include <Psapi.h> #if _MSC_VER >= 1900#pragma comment(lib, "legacy_stdio_definitions.lib")FILE _iob[] = {*stdin, *stdout, *stderr};extern "C" FILE * __cdecl __iob_func(void) {    return _iob;}#endif #endif  #ifdef __APPLE__#include <CoreFoundation/CoreFoundation.h>#endif  #if defined(Q_OS_LINUX) || defined(Q_OS_MAC)#include <signal.h>#include <cerrno>#endif #include <QtCore/QDebug>#include <QDateTime>#include <QElapsedTimer>#include <QTimer>#include <QProcess>#include <QSysInfo>#include <QThread> #include <BuildInfo.h> #include "LogHandler.h"#include "NumericalConstants.h"#include "OctalCode.h"#include "SharedLogging.h" //     Global instances are stored inside the QApplication properties// to provide a single instance across DLL boundaries.// This is something we cannot do here since several DLLs// and our main binaries statically link this "shared" library// resulting in multiple static memory blocks in different constexts//     But we need to be able to use global instances before the QApplication// is setup, so to accomplish that we stage the global instances in a local// map and setup a pre routine (commitGlobalInstances) that will run in the// QApplication constructor and commit all the staged instances to the// QApplication properties.//     Note: One of the side effects of this, is that no DLL loaded before// the QApplication is constructed, can expect to access the existing staged// global instanced. For this reason, we advise all DLLs be loaded after// the QApplication is instanced.static std::mutex stagedGlobalInstancesMutex;static std::unordered_map<std::string, QVariant> stagedGlobalInstances; std::mutex& globalInstancesMutex() {    return stagedGlobalInstancesMutex;} static void commitGlobalInstances() {    std::unique_lock<std::mutex> lock(globalInstancesMutex());    for (const auto& it : stagedGlobalInstances) {        qApp->setProperty(it.first.c_str(), it.second);    }    stagedGlobalInstances.clear();} // This call is necessary for global instances to work across DLL boundaries// Ideally, this founction would be called at the top of the main function.// See description at the top of the file.void setupGlobalInstances() {    qAddPreRoutine(commitGlobalInstances);} QVariant getGlobalInstance(const char* propertyName) {    if (qApp) {        return qApp->property(propertyName);    } else {        auto it = stagedGlobalInstances.find(propertyName);        if (it != stagedGlobalInstances.end()) {            return it->second;        }    }    return QVariant();} void setGlobalInstance(const char* propertyName, const QVariant& variant) {    if (qApp) {        qApp->setProperty(propertyName, variant);    } else {        stagedGlobalInstances[propertyName] = variant;    }} static qint64 usecTimestampNowAdjust = 0; // in usecvoid usecTimestampNowForceClockSkew(qint64 clockSkew) {    ::usecTimestampNowAdjust = clockSkew;} quint64 usecTimestampNow(bool wantDebug) {    using namespace std::chrono;    static const auto unixEpoch = system_clock::from_time_t(0);    return duration_cast<microseconds>(system_clock::now() - unixEpoch).count() + usecTimestampNowAdjust;} float secTimestampNow() {    static const auto START_TIME = usecTimestampNow();    const auto nowUsecs = usecTimestampNow() - START_TIME;    const auto nowMsecs = nowUsecs / USECS_PER_MSEC;    return (float)nowMsecs / MSECS_PER_SECOND;} float randFloat() {    return (rand() % 10000)/10000.0f;} int randIntInRange (int min, int max) {    return min + (rand() % ((max + 1) - min));} float randFloatInRange (float min,float max) {    return min + ((rand() % 10000)/10000.0f * (max-min));} float randomSign() {    return randomBoolean() ? -1.0 : 1.0;} unsigned char randomColorValue(int miniumum) {    return miniumum + (rand() % (256 - miniumum));} bool randomBoolean() {    return rand() % 2;} bool shouldDo(float desiredInterval, float deltaTime) {    return randFloat() < deltaTime / desiredInterval;} void outputBufferBits(const unsigned char* buffer, int length, QDebug* continuedDebug) {    for (int i = 0; i < length; i++) {        outputBits(buffer[i], continuedDebug);    }} void outputBits(unsigned char byte, QDebug* continuedDebug) {    QDebug debug = qDebug().nospace();     if (continuedDebug) {        debug = *continuedDebug;        debug.nospace();    }     QString resultString;    QTextStream qts (&resultString);     qts << "[ ";    qts << qSetFieldWidth(3) << byte << qSetFieldWidth(0);    qts << qSetPadChar('0');     if (isalnum(byte)) {        qts << " (" << QString(byte) << ")   : ";    } else {        qts << " (0x" << Qt::hex << qSetFieldWidth(2) << byte << qSetFieldWidth(0) << "): ";    }     qts << Qt::bin << qSetFieldWidth(8) << byte << qSetFieldWidth(0);    qts << " ]";     debug.noquote();    debug << resultString;} int numberOfOnes(unsigned char byte) {     static const int nbits[256] = {        0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,        4,3,4,4,5,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,        4,5,3,4,4,5,4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,        3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,        4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,1,2,2,3,2,3,3,        4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,        3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,        6,6,7,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,        4,5,5,6,5,6,6,7,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,        6,5,6,6,7,5,6,6,7,6,7,7,8    };     return nbits[(unsigned char) byte]; } bool oneAtBit(unsigned char byte, int bitIndex) {    return (byte >> (7 - bitIndex) & 1);} void setAtBit(unsigned char& byte, int bitIndex) {    byte |= (1 << (7 - bitIndex));} bool oneAtBit16(unsigned short word, int bitIndex) {    return (word >> (15 - bitIndex) & 1);} void setAtBit16(unsigned short& word, int bitIndex) {    word |= (1 << (15 - bitIndex));}  void clearAtBit(unsigned char& byte, int bitIndex) {    if (oneAtBit(byte, bitIndex)) {        byte -= (1 << (7 - bitIndex));    }} int  getSemiNibbleAt(unsigned short word, int bitIndex) {    return (word >> (14 - bitIndex) & 3); // semi-nibbles store 00, 01, 10, or 11} int getNthBit(unsigned char byte, int ordinal) {    const int ERROR_RESULT = -1;    const int MIN_ORDINAL = 1;    const int MAX_ORDINAL = 8;    if (ordinal < MIN_ORDINAL || ordinal > MAX_ORDINAL) {        return ERROR_RESULT;    }    int bitsSet = 0;    for (int bitIndex = 0; bitIndex < MAX_ORDINAL; bitIndex++) {        if (oneAtBit(byte, bitIndex)) {            bitsSet++;        }        if (bitsSet == ordinal) {            return bitIndex;        }    }    return ERROR_RESULT;} void setSemiNibbleAt(unsigned short& word, int bitIndex, int value) {    //assert(value <= 3 && value >= 0);    word |= ((value & 3) << (14 - bitIndex)); // semi-nibbles store 00, 01, 10, or 11} bool isInEnvironment(const char* environment) {    char* environmentString = getenv("HIFI_ENVIRONMENT");    return (environmentString && strcmp(environmentString, environment) == 0);} //////////////////////////////////////////////////////////////////////////////////////////// Function:    getCmdOption()// Description: Handy little function to tell you if a command line flag and option was//              included while launching the application, and to get the option value//              immediately following the flag. For example if you ran://                      ./app -i filename.txt//              then you're using the "-i" flag to set the input file name.// Usage:       char * inputFilename = getCmdOption(argc, argv, "-i");// Complaints:  Brad :)const char* getCmdOption(int argc, const char * argv[],const char* option) {    // check each arg    for (int i=0; i < argc; i++) {        // if the arg matches the desired option        if (strcmp(option,argv[i])==0 && i+1 < argc) {            // then return the next option            return argv[i+1];        }    }    return NULL;} //////////////////////////////////////////////////////////////////////////////////////////// Function:    getCmdOption()// Description: Handy little function to tell you if a command line option flag was//              included while launching the application. Returns bool true/false// Usage:       bool wantDump   = cmdOptionExists(argc, argv, "-d");// Complaints:  Brad :) bool cmdOptionExists(int argc, const char * argv[],const char* option) {    // check each arg    for (int i=0; i < argc; i++) {        // if the arg matches the desired option        if (strcmp(option,argv[i])==0) {            // then return the next option            return true;        }    }    return false;} void sharedMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message) {    fprintf(stdout, "%s", message.toLocal8Bit().constData());} unsigned char* pointToOctalCode(float x, float y, float z, float s) {    return pointToVoxel(x, y, z, s);} /// Given a universal point with location x,y,z this will return the voxel/// voxel code corresponding to the closest voxel which encloses a cube with/// lower corners at x,y,z, having side of length S./// The input values x,y,z range 0.0 <= v < 1.0/// IMPORTANT: The voxel is returned to you a buffer which you MUST delete when you are/// done with it.unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r, unsigned char g, unsigned char b ) {     // special case for size 1, the root node    if (s >= 1.0f) {        unsigned char* voxelOut = new unsigned char;        *voxelOut = 0;        return voxelOut;    }     float xTest, yTest, zTest, sTest;    xTest = yTest = zTest = sTest = 0.5f;     // First determine the voxelSize that will properly encode a    // voxel of size S.    unsigned int voxelSizeInOctets = 1;    while (sTest > s) {        sTest /= 2.0f;        voxelSizeInOctets++;    }     auto voxelSizeInBytes = bytesRequiredForCodeLength(voxelSizeInOctets); // (voxelSizeInBits/8)+1;    auto voxelBufferSize = voxelSizeInBytes + sizeof(glm::u8vec3); // 3 for color     // allocate our resulting buffer    unsigned char* voxelOut = new unsigned char[voxelBufferSize];     // first byte of buffer is always our size in octets    voxelOut[0]=voxelSizeInOctets;     sTest = 0.5f; // reset sTest so we can do this again.     unsigned char byte = 0; // we will be adding coding bits here    int bitInByteNDX = 0; // keep track of where we are in byte as we go    int byteNDX = 1; // keep track of where we are in buffer of bytes as we go    unsigned int octetsDone = 0;     // Now we actually fill out the voxel code    while (octetsDone < voxelSizeInOctets) {        if (x >= xTest) {            //<write 1 bit>            byte = (byte << 1) | true;            xTest += sTest/2.0f;        } else {            //<write 0 bit;>            byte = (byte << 1) | false;            xTest -= sTest/2.0f;        }        bitInByteNDX++;        // If we've reached the last bit of the byte, then we want to copy this byte        // into our buffer. And get ready to start on a new byte        if (bitInByteNDX == 8) {            voxelOut[byteNDX]=byte;            byteNDX++;            bitInByteNDX=0;            byte=0;        }         if (y >= yTest) {            //<write 1 bit>            byte = (byte << 1) | true;            yTest += sTest/2.0f;        } else {            //<write 0 bit;>            byte = (byte << 1) | false;            yTest -= sTest/2.0f;        }        bitInByteNDX++;        // If we've reached the last bit of the byte, then we want to copy this byte        // into our buffer. And get ready to start on a new byte        if (bitInByteNDX == 8) {            voxelOut[byteNDX]=byte;            byteNDX++;            bitInByteNDX=0;            byte=0;        }         if (z >= zTest) {            //<write 1 bit>            byte = (byte << 1) | true;            zTest += sTest/2.0f;        } else {            //<write 0 bit;>            byte = (byte << 1) | false;            zTest -= sTest/2.0f;        }        bitInByteNDX++;        // If we've reached the last bit of the byte, then we want to copy this byte        // into our buffer. And get ready to start on a new byte        if (bitInByteNDX == 8) {            voxelOut[byteNDX]=byte;            byteNDX++;            bitInByteNDX=0;            byte=0;        }         octetsDone++;        sTest /= 2.0f;    }     // If we've got here, and we didn't fill the last byte, we need to zero pad this    // byte before we copy it into our buffer.    if (bitInByteNDX > 0 && bitInByteNDX < 8) {        // Pad the last byte        while (bitInByteNDX < 8) {            byte = (byte << 1) | false;            bitInByteNDX++;        }         // Copy it into our output buffer        voxelOut[byteNDX]=byte;        byteNDX++;    }    // copy color data    voxelOut[byteNDX]=r;    voxelOut[byteNDX+1]=g;    voxelOut[byteNDX+2]=b;     return voxelOut;} void printVoxelCode(unsigned char* voxelCode) {    unsigned char octets = voxelCode[0];    unsigned int voxelSizeInBits = octets*3;    unsigned int voxelSizeInBytes = (voxelSizeInBits/8)+1;    unsigned int voxelSizeInOctets = (voxelSizeInBits/3);    unsigned int voxelBufferSize = voxelSizeInBytes+1+3; // 1 for size, 3 for color     qCDebug(shared, "octets=%d",octets);    qCDebug(shared, "voxelSizeInBits=%d",voxelSizeInBits);    qCDebug(shared, "voxelSizeInBytes=%d",voxelSizeInBytes);    qCDebug(shared, "voxelSizeInOctets=%d",voxelSizeInOctets);    qCDebug(shared, "voxelBufferSize=%d",voxelBufferSize);     for(unsigned int i=0; i < voxelBufferSize; i++) {        QDebug voxelBufferDebug = qDebug();        voxelBufferDebug << "i =" << i;        outputBits(voxelCode[i], &voxelBufferDebug);    }} #ifdef _WIN32void usleep(int waitTime) {    // Use QueryPerformanceCounter for least overhead    LARGE_INTEGER now; // ticks    QueryPerformanceCounter(&now);     static int64_t ticksPerSec = 0;    if (ticksPerSec == 0) {        LARGE_INTEGER frequency;        QueryPerformanceFrequency(&frequency);        ticksPerSec = frequency.QuadPart;    }     // order ops to avoid loss in precision    int64_t waitTicks = (ticksPerSec * waitTime) / USECS_PER_SECOND;    int64_t sleepTicks = now.QuadPart + waitTicks;     // Busy wait with sleep/yield where possible    while (true) {        QueryPerformanceCounter(&now);        if (now.QuadPart >= sleepTicks) {            break;        }         // Sleep if we have at least 1ms to spare        const int64_t MIN_SLEEP_USECS = 1000;        // msleep is allowed to overshoot, so give it a 100us berth

Lines 1–500 of 1214.