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

This commit is contained in:
Andrzej Kapolka 2014-11-06 17:05:49 -08:00
commit ae71bb671b
56 changed files with 1801 additions and 478 deletions

View file

@ -61,7 +61,7 @@
const float LOUDNESS_TO_DISTANCE_RATIO = 0.00001f;
const float DEFAULT_ATTENUATION_PER_DOUBLING_IN_DISTANCE = 0.18;
const float DEFAULT_NOISE_MUTING_THRESHOLD = 0.003f;
const QString AUDIO_MIXER_LOGGING_TARGET_NAME = "audio-mixer";
const QString AUDIO_ENV_GROUP_KEY = "audio_env";
const QString AUDIO_BUFFER_GROUP_KEY = "audio_buffer";
@ -78,12 +78,17 @@ bool AudioMixer::_printStreamStats = false;
bool AudioMixer::_enableFilter = true;
bool AudioMixer::shouldMute(float quietestFrame, float loudestFrame) {
return (quietestFrame > _noiseMutingThreshold);
}
AudioMixer::AudioMixer(const QByteArray& packet) :
ThreadedAssignment(packet),
_trailingSleepRatio(1.0f),
_minAudibilityThreshold(LOUDNESS_TO_DISTANCE_RATIO / 2.0f),
_performanceThrottlingRatio(0.0f),
_attenuationPerDoublingInDistance(DEFAULT_ATTENUATION_PER_DOUBLING_IN_DISTANCE),
_noiseMutingThreshold(DEFAULT_NOISE_MUTING_THRESHOLD),
_numStatFrames(0),
_sumListeners(0),
_sumMixes(0),
@ -136,6 +141,11 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* l
return 0;
}
// if the stream should be muted, bail
if (shouldMute(streamToAdd->getQuietestTrailingFrameLoudness(), streamToAdd->getLoudestTrailingFrameLoudness())) {
return 0;
}
float bearingRelativeAngleToSource = 0.0f;
float attenuationCoefficient = 1.0f;
int numSamplesDelay = 0;
@ -353,7 +363,7 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* l
}
}
if (!sourceIsSelf && _enableFilter) {
if (!sourceIsSelf && _enableFilter && !streamToAdd->ignorePenumbraFilter()) {
const float TWO_OVER_PI = 2.0f / PI;
@ -400,15 +410,12 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* l
penumbraFilterGainR += (1.f - penumbraFilterGainR) * (1.f - distanceBetween / RADIUS_OF_HEAD);
}
#if 0
qDebug() << "gainL="
<< penumbraFilterGainL
<< "gainR="
<< penumbraFilterGainR
<< "angle="
<< -bearingRelativeAngleToSource;
#endif
bool wantDebug = false;
if (wantDebug) {
qDebug() << "gainL=" << penumbraFilterGainL
<< "gainR=" << penumbraFilterGainR
<< "angle=" << -bearingRelativeAngleToSource;
}
// Get our per listener/source data so we can get our filter
AudioFilterHSF1s& penumbraFilter = listenerNodeData->getListenerSourcePairData(streamUUID)->getPenumbraFilter();
@ -1003,7 +1010,17 @@ void AudioMixer::parseSettingsObject(const QJsonObject &settingsObject) {
qDebug() << "Attenuation per doubling in distance changed to" << _attenuationPerDoublingInDistance;
}
}
const QString NOISE_MUTING_THRESHOLD = "noise_muting_threshold";
if (audioEnvGroupObject[NOISE_MUTING_THRESHOLD].isString()) {
bool ok = false;
float noiseMutingThreshold = audioEnvGroupObject[NOISE_MUTING_THRESHOLD].toString().toFloat(&ok);
if (ok) {
_noiseMutingThreshold = noiseMutingThreshold;
qDebug() << "Noise muting threshold changed to" << _noiseMutingThreshold;
}
}
const QString FILTER_KEY = "enable_filter";
if (audioEnvGroupObject[FILTER_KEY].isBool()) {
_enableFilter = audioEnvGroupObject[FILTER_KEY].toBool();

View file

@ -59,6 +59,8 @@ private:
int16_t _mixSamples[NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + (SAMPLE_PHASE_DELAY_AT_90 * 2)];
void perSecondActions();
bool shouldMute(float quietestFrame, float loudestFrame);
QString getReadPendingDatagramsCallsPerSecondsStatsString() const;
QString getReadPendingDatagramsPacketsPerCallStatsString() const;
@ -71,6 +73,7 @@ private:
float _minAudibilityThreshold;
float _performanceThrottlingRatio;
float _attenuationPerDoublingInDistance;
float _noiseMutingThreshold;
int _numStatFrames;
int _sumListeners;
int _sumMixes;

View file

@ -34,6 +34,7 @@ public:
virtual const char* getMyLoggingServerTargetName() const { return MODEL_SERVER_LOGGING_TARGET_NAME; }
virtual const char* getMyDefaultPersistFilename() const { return LOCAL_MODELS_PERSIST_FILE; }
virtual PacketType getMyEditNackType() const { return PacketTypeEntityEditNack; }
virtual QString getMyDomainSettingsKey() const { return QString("entity_server_settings"); }
// subclass may implement these method
virtual void beforeRun();

View file

@ -98,15 +98,28 @@ void OctreeInboundPacketProcessor::processPacket(const SharedNodePointer& sendin
unsigned short int sequence = (*((unsigned short int*)(packetData + numBytesPacketHeader)));
quint64 sentAt = (*((quint64*)(packetData + numBytesPacketHeader + sizeof(sequence))));
quint64 arrivedAt = usecTimestampNow();
if (sentAt > arrivedAt) {
if (debugProcessPacket || _myServer->wantsDebugReceiving()) {
qDebug() << "unreasonable sentAt=" << sentAt << " usecs";
qDebug() << "setting sentAt to arrivedAt=" << arrivedAt << " usecs";
}
sentAt = arrivedAt;
}
quint64 transitTime = arrivedAt - sentAt;
int editsInPacket = 0;
quint64 processTime = 0;
quint64 lockWaitTime = 0;
if (debugProcessPacket || _myServer->wantsDebugReceiving()) {
qDebug() << "PROCESSING THREAD: got '" << packetType << "' packet - " << _receivedPacketCount
<< " command from client receivedBytes=" << packet.size()
<< " sequence=" << sequence << " transitTime=" << transitTime << " usecs";
qDebug() << "PROCESSING THREAD: got '" << packetType << "' packet - " << _receivedPacketCount << " command from client";
qDebug() << " receivedBytes=" << packet.size();
qDebug() << " sequence=" << sequence;
qDebug() << " sentAt=" << sentAt << " usecs";
qDebug() << " arrivedAt=" << arrivedAt << " usecs";
qDebug() << " transitTime=" << transitTime << " usecs";
qDebug() << " sendingNode->getClockSkewUsec()=" << sendingNode->getClockSkewUsec() << " usecs";
}
if (debugProcessPacket) {

View file

@ -452,11 +452,10 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus
_myServer->getOctree()->lockForRead();
quint64 lockWaitEnd = usecTimestampNow();
lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart);
quint64 encodeStart = usecTimestampNow();
bytesWritten = _myServer->getOctree()->encodeTreeBitstream(subTree, &_packetData, nodeData->elementBag, params);
quint64 encodeEnd = usecTimestampNow();
encodeElapsedUsec = (float)(encodeEnd - encodeStart);

View file

@ -900,85 +900,206 @@ void OctreeServer::setupDatagramProcessingThread() {
// start the datagram processing thread
_datagramProcessingThread->start();
}
bool OctreeServer::readOptionBool(const QString& optionName, const QJsonObject& settingsSectionObject, bool& result) {
result = false; // assume it doesn't exist
bool optionAvailable = false;
QString argName = "--" + optionName;
bool argExists = cmdOptionExists(_argc, _argv, qPrintable(argName));
if (argExists) {
optionAvailable = true;
result = argExists;
qDebug() << "From payload arguments: " << qPrintable(argName) << ":" << result;
} else if (settingsSectionObject.contains(optionName)) {
optionAvailable = true;
result = settingsSectionObject[optionName].toBool();
qDebug() << "From domain settings: " << qPrintable(optionName) << ":" << result;
}
return optionAvailable;
}
bool OctreeServer::readOptionInt(const QString& optionName, const QJsonObject& settingsSectionObject, int& result) {
bool optionAvailable = false;
QString argName = "--" + optionName;
const char* argValue = getCmdOption(_argc, _argv, qPrintable(argName));
if (argValue) {
optionAvailable = true;
result = atoi(argValue);
qDebug() << "From payload arguments: " << qPrintable(argName) << ":" << result;
} else if (settingsSectionObject.contains(optionName)) {
optionAvailable = true;
result = settingsSectionObject[optionName].toString().toInt(&optionAvailable);
if (optionAvailable) {
qDebug() << "From domain settings: " << qPrintable(optionName) << ":" << result;
}
}
return optionAvailable;
}
bool OctreeServer::readOptionString(const QString& optionName, const QJsonObject& settingsSectionObject, QString& result) {
bool optionAvailable = false;
QString argName = "--" + optionName;
const char* argValue = getCmdOption(_argc, _argv, qPrintable(argName));
if (argValue) {
optionAvailable = true;
result = QString(argValue);
qDebug() << "From payload arguments: " << qPrintable(argName) << ":" << qPrintable(result);
} else if (settingsSectionObject.contains(optionName)) {
optionAvailable = true;
result = settingsSectionObject[optionName].toString();
qDebug() << "From domain settings: " << qPrintable(optionName) << ":" << qPrintable(result);
}
return optionAvailable;
}
void OctreeServer::readConfiguration() {
// if the assignment had a payload, read and parse that
if (getPayload().size() > 0) {
parsePayload();
}
// wait until we have the domain-server settings, otherwise we bail
NodeList* nodeList = NodeList::getInstance();
DomainHandler& domainHandler = nodeList->getDomainHandler();
qDebug() << "Waiting for domain settings from domain-server.";
// block until we get the settingsRequestComplete signal
QEventLoop loop;
connect(&domainHandler, &DomainHandler::settingsReceived, &loop, &QEventLoop::quit);
connect(&domainHandler, &DomainHandler::settingsReceiveFail, &loop, &QEventLoop::quit);
domainHandler.requestDomainSettings();
loop.exec();
if (domainHandler.getSettingsObject().isEmpty()) {
qDebug() << "No settings object from domain-server.";
}
const QJsonObject& settingsObject = domainHandler.getSettingsObject();
QString settingsKey = getMyDomainSettingsKey();
QJsonObject settingsSectionObject = settingsObject[settingsKey].toObject();
if (!readOptionString(QString("statusHost"), settingsSectionObject, _statusHost) || _statusHost.isEmpty()) {
_statusHost = getLocalAddress().toString();
}
qDebug("statusHost=%s", qPrintable(_statusHost));
if (readOptionInt(QString("statusPort"), settingsSectionObject, _statusPort)) {
initHTTPManager(_statusPort);
qDebug() << "statusPort=" << _statusPort;
} else {
qDebug() << "statusPort= DISABLED";
}
QString jurisdictionFile;
if (readOptionString(QString("jurisdictionFile"), settingsSectionObject, jurisdictionFile)) {
qDebug("jurisdictionFile=%s", qPrintable(jurisdictionFile));
qDebug("about to readFromFile().... jurisdictionFile=%s", qPrintable(jurisdictionFile));
_jurisdiction = new JurisdictionMap(qPrintable(jurisdictionFile));
qDebug("after readFromFile().... jurisdictionFile=%s", qPrintable(jurisdictionFile));
} else {
QString jurisdictionRoot;
bool hasRoot = readOptionString(QString("jurisdictionRoot"), settingsSectionObject, jurisdictionRoot);
QString jurisdictionEndNodes;
bool hasEndNodes = readOptionString(QString("jurisdictionEndNodes"), settingsSectionObject, jurisdictionEndNodes);
if (hasRoot || hasEndNodes) {
_jurisdiction = new JurisdictionMap(qPrintable(jurisdictionRoot), qPrintable(jurisdictionEndNodes));
}
}
readOptionBool(QString("verboseDebug"), settingsSectionObject, _verboseDebug);
qDebug("verboseDebug=%s", debug::valueOf(_verboseDebug));
readOptionBool(QString("debugSending"), settingsSectionObject, _debugSending);
qDebug("debugSending=%s", debug::valueOf(_debugSending));
readOptionBool(QString("debugReceiving"), settingsSectionObject, _debugReceiving);
qDebug("debugReceiving=%s", debug::valueOf(_debugReceiving));
bool noPersist;
readOptionBool(QString("NoPersist"), settingsSectionObject, noPersist);
_wantPersist = !noPersist;
qDebug("wantPersist=%s", debug::valueOf(_wantPersist));
if (_wantPersist) {
QString persistFilename;
if (!readOptionString(QString("persistFilename"), settingsSectionObject, persistFilename)) {
persistFilename = getMyDefaultPersistFilename();
}
strcpy(_persistFilename, qPrintable(persistFilename));
qDebug("persistFilename=%s", _persistFilename);
} else {
qDebug("persistFilename= DISABLED");
}
// Debug option to demonstrate that the server's local time does not
// need to be in sync with any other network node. This forces clock
// skew for the individual server node
int clockSkew;
if (readOptionInt(QString("clockSkew"), settingsSectionObject, clockSkew)) {
usecTimestampNowForceClockSkew(clockSkew);
qDebug("clockSkew=%d", clockSkew);
}
// Check to see if the user passed in a command line option for setting packet send rate
int packetsPerSecondPerClientMax = -1;
if (readOptionInt(QString("packetsPerSecondPerClientMax"), settingsSectionObject, packetsPerSecondPerClientMax)) {
_packetsPerClientPerInterval = packetsPerSecondPerClientMax / INTERVALS_PER_SECOND;
if (_packetsPerClientPerInterval < 1) {
_packetsPerClientPerInterval = 1;
}
}
qDebug("packetsPerSecondPerClientMax=%d _packetsPerClientPerInterval=%d",
packetsPerSecondPerClientMax, _packetsPerClientPerInterval);
// Check to see if the user passed in a command line option for setting packet send rate
int packetsPerSecondTotalMax = -1;
if (readOptionInt(QString("packetsPerSecondTotalMax"), settingsSectionObject, packetsPerSecondTotalMax)) {
_packetsTotalPerInterval = packetsPerSecondTotalMax / INTERVALS_PER_SECOND;
if (_packetsTotalPerInterval < 1) {
_packetsTotalPerInterval = 1;
}
}
qDebug("packetsPerSecondTotalMax=%d _packetsTotalPerInterval=%d",
packetsPerSecondTotalMax, _packetsTotalPerInterval);
readAdditionalConfiguration(settingsSectionObject);
}
void OctreeServer::run() {
qInstallMessageHandler(LogHandler::verboseMessageHandler);
_safeServerName = getMyServerName();
// Before we do anything else, create our tree...
OctreeElement::resetPopulationStatistics();
_tree = createTree();
_tree->setIsServer(true);
// make sure our NodeList knows what type we are
NodeList* nodeList = NodeList::getInstance();
nodeList->setOwnerType(getMyNodeType());
// use common init to setup common timers and logging
commonInit(getMyLoggingServerTargetName(), getMyNodeType());
setupDatagramProcessingThread();
// Now would be a good time to parse our arguments, if we got them as assignment
if (getPayload().size() > 0) {
parsePayload();
}
// read the configuration from either the payload or the domain server configuration
readConfiguration();
beforeRun(); // after payload has been processed
qInstallMessageHandler(LogHandler::verboseMessageHandler);
const char* STATUS_PORT = "--statusPort";
const char* statusPort = getCmdOption(_argc, _argv, STATUS_PORT);
if (statusPort) {
_statusPort = atoi(statusPort);
initHTTPManager(_statusPort);
}
const char* STATUS_HOST = "--statusHost";
const char* statusHost = getCmdOption(_argc, _argv, STATUS_HOST);
if (statusHost) {
qDebug("--statusHost=%s", statusHost);
_statusHost = statusHost;
} else {
_statusHost = getLocalAddress().toString();
}
qDebug("statusHost=%s", qPrintable(_statusHost));
const char* JURISDICTION_FILE = "--jurisdictionFile";
const char* jurisdictionFile = getCmdOption(_argc, _argv, JURISDICTION_FILE);
if (jurisdictionFile) {
qDebug("jurisdictionFile=%s", jurisdictionFile);
qDebug("about to readFromFile().... jurisdictionFile=%s", jurisdictionFile);
_jurisdiction = new JurisdictionMap(jurisdictionFile);
qDebug("after readFromFile().... jurisdictionFile=%s", jurisdictionFile);
} else {
const char* JURISDICTION_ROOT = "--jurisdictionRoot";
const char* jurisdictionRoot = getCmdOption(_argc, _argv, JURISDICTION_ROOT);
if (jurisdictionRoot) {
qDebug("jurisdictionRoot=%s", jurisdictionRoot);
}
const char* JURISDICTION_ENDNODES = "--jurisdictionEndNodes";
const char* jurisdictionEndNodes = getCmdOption(_argc, _argv, JURISDICTION_ENDNODES);
if (jurisdictionEndNodes) {
qDebug("jurisdictionEndNodes=%s", jurisdictionEndNodes);
}
if (jurisdictionRoot || jurisdictionEndNodes) {
_jurisdiction = new JurisdictionMap(jurisdictionRoot, jurisdictionEndNodes);
}
}
NodeList* nodeList = NodeList::getInstance();
nodeList->setOwnerType(getMyNodeType());
connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), SLOT(nodeAdded(SharedNodePointer)));
connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)),SLOT(nodeKilled(SharedNodePointer)));
// we need to ask the DS about agents so we can ping/reply with them
nodeList->addNodeTypeToInterestSet(NodeType::Agent);
#ifndef WIN32
setvbuf(stdout, NULL, _IOLBF, 0);
#endif
@ -987,39 +1108,9 @@ void OctreeServer::run() {
srand((unsigned)time(0));
const char* VERBOSE_DEBUG = "--verboseDebug";
_verboseDebug = cmdOptionExists(_argc, _argv, VERBOSE_DEBUG);
qDebug("verboseDebug=%s", debug::valueOf(_verboseDebug));
const char* DEBUG_SENDING = "--debugSending";
_debugSending = cmdOptionExists(_argc, _argv, DEBUG_SENDING);
qDebug("debugSending=%s", debug::valueOf(_debugSending));
const char* DEBUG_RECEIVING = "--debugReceiving";
_debugReceiving = cmdOptionExists(_argc, _argv, DEBUG_RECEIVING);
qDebug("debugReceiving=%s", debug::valueOf(_debugReceiving));
// By default we will persist, if you want to disable this, then pass in this parameter
const char* NO_PERSIST = "--NoPersist";
if (cmdOptionExists(_argc, _argv, NO_PERSIST)) {
_wantPersist = false;
}
qDebug("wantPersist=%s", debug::valueOf(_wantPersist));
// if we want Persistence, set up the local file and persist thread
if (_wantPersist) {
// Check to see if the user passed in a command line option for setting packet send rate
const char* PERSIST_FILENAME = "--persistFilename";
const char* persistFilenameParameter = getCmdOption(_argc, _argv, PERSIST_FILENAME);
if (persistFilenameParameter) {
strcpy(_persistFilename, persistFilenameParameter);
} else {
strcpy(_persistFilename, getMyDefaultPersistFilename());
}
qDebug("persistFilename=%s", _persistFilename);
// now set up PersistThread
_persistThread = new OctreePersistThread(_tree, _persistFilename);
if (_persistThread) {
@ -1027,41 +1118,6 @@ void OctreeServer::run() {
}
}
// Debug option to demonstrate that the server's local time does not
// need to be in sync with any other network node. This forces clock
// skew for the individual server node
const char* CLOCK_SKEW = "--clockSkew";
const char* clockSkewOption = getCmdOption(_argc, _argv, CLOCK_SKEW);
if (clockSkewOption) {
int clockSkew = atoi(clockSkewOption);
usecTimestampNowForceClockSkew(clockSkew);
qDebug("clockSkewOption=%s clockSkew=%d", clockSkewOption, clockSkew);
}
// Check to see if the user passed in a command line option for setting packet send rate
const char* PACKETS_PER_SECOND_PER_CLIENT_MAX = "--packetsPerSecondPerClientMax";
const char* packetsPerSecondPerClientMax = getCmdOption(_argc, _argv, PACKETS_PER_SECOND_PER_CLIENT_MAX);
if (packetsPerSecondPerClientMax) {
_packetsPerClientPerInterval = atoi(packetsPerSecondPerClientMax) / INTERVALS_PER_SECOND;
if (_packetsPerClientPerInterval < 1) {
_packetsPerClientPerInterval = 1;
}
}
qDebug("packetsPerSecondPerClientMax=%s _packetsPerClientPerInterval=%d",
packetsPerSecondPerClientMax, _packetsPerClientPerInterval);
// Check to see if the user passed in a command line option for setting packet send rate
const char* PACKETS_PER_SECOND_TOTAL_MAX = "--packetsPerSecondTotalMax";
const char* packetsPerSecondTotalMax = getCmdOption(_argc, _argv, PACKETS_PER_SECOND_TOTAL_MAX);
if (packetsPerSecondTotalMax) {
_packetsTotalPerInterval = atoi(packetsPerSecondTotalMax) / INTERVALS_PER_SECOND;
if (_packetsTotalPerInterval < 1) {
_packetsTotalPerInterval = 1;
}
}
qDebug("packetsPerSecondTotalMax=%s _packetsTotalPerInterval=%d",
packetsPerSecondTotalMax, _packetsTotalPerInterval);
HifiSockAddr senderSockAddr;
// set up our jurisdiction broadcaster...

View file

@ -69,6 +69,7 @@ public:
virtual const char* getMyLoggingServerTargetName() const = 0;
virtual const char* getMyDefaultPersistFilename() const = 0;
virtual PacketType getMyEditNackType() const = 0;
virtual QString getMyDomainSettingsKey() const { return QString("octree_server_settings"); }
// subclass may implement these method
virtual void beforeRun() { }
@ -131,6 +132,11 @@ public slots:
void readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr);
protected:
bool readOptionBool(const QString& optionName, const QJsonObject& settingsSectionObject, bool& result);
bool readOptionInt(const QString& optionName, const QJsonObject& settingsSectionObject, int& result);
bool readOptionString(const QString& optionName, const QJsonObject& settingsSectionObject, QString& result);
void readConfiguration();
virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject) { };
void parsePayload();
void initHTTPManager(int port);
void resetSendingStats();

View file

@ -82,18 +82,18 @@ int VoxelServer::sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNod
}
void VoxelServer::beforeRun() {
void VoxelServer::readAdditionalConfiguration(const QJsonObject& settingsSectionObject) {
// should we send environments? Default is yes, but this command line suppresses sending
const char* SEND_ENVIRONMENTS = "--sendEnvironments";
bool dontSendEnvironments = !cmdOptionExists(_argc, _argv, SEND_ENVIRONMENTS);
readOptionBool(QString("sendEnvironments"), settingsSectionObject, _sendEnvironments);
bool dontSendEnvironments = !_sendEnvironments;
if (dontSendEnvironments) {
qDebug("Sending environments suppressed...");
_sendEnvironments = false;
} else {
_sendEnvironments = true;
// should we send environments? Default is yes, but this command line suppresses sending
const char* MINIMAL_ENVIRONMENT = "--minimalEnvironment";
_sendMinimalEnvironment = cmdOptionExists(_argc, _argv, MINIMAL_ENVIRONMENT);
//const char* MINIMAL_ENVIRONMENT = "--minimalEnvironment";
//_sendMinimalEnvironment = cmdOptionExists(_argc, _argv, MINIMAL_ENVIRONMENT);
readOptionBool(QString("minimalEnvironment"), settingsSectionObject, _sendMinimalEnvironment);
qDebug("Using Minimal Environment=%s", debug::valueOf(_sendMinimalEnvironment));
}
qDebug("Sending environments=%s", debug::valueOf(_sendEnvironments));

View file

@ -43,12 +43,15 @@ public:
virtual const char* getMyLoggingServerTargetName() const { return VOXEL_SERVER_LOGGING_TARGET_NAME; }
virtual const char* getMyDefaultPersistFilename() const { return LOCAL_VOXELS_PERSIST_FILE; }
virtual PacketType getMyEditNackType() const { return PacketTypeVoxelEditNack; }
virtual QString getMyDomainSettingsKey() const { return QString("voxel_server_settings"); }
// subclass may implement these method
virtual void beforeRun();
virtual bool hasSpecialPacketToSend(const SharedNodePointer& node);
virtual int sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent);
protected:
virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject);
private:
bool _sendEnvironments;
bool _sendMinimalEnvironment;

View file

@ -89,6 +89,14 @@
"default": "0.18",
"advanced": false
},
{
"name": "noise_muting_threshold",
"label": "Noise Muting Threshold",
"help": "Loudness value for noise background between 0 and 1.0 (0: mute everyone, 1.0: never mute)",
"placeholder": "0.003",
"default": "0.003",
"advanced": false
},
{
"name": "enable_filter",
"type": "checkbox",
@ -262,5 +270,106 @@
"advanced": true
}
]
}
},
{
"name": "entity_server_settings",
"label": "Entity Server Settings",
"assignment-types": [6],
"settings": [
{
"name": "statusHost",
"label": "Status Hostname",
"help": "host name or IP address of the server for accessing the status page",
"placeholder": "",
"default": "",
"advanced": true
},
{
"name": "statusPort",
"label": "Status Port",
"help": "port of the server for accessing the status page",
"placeholder": "",
"default": "",
"advanced": true
},
{
"name": "verboseDebug",
"type": "checkbox",
"help": "lots of debugging",
"default": false,
"advanced": true
},
{
"name": "debugReceiving",
"type": "checkbox",
"help": "extra debugging on receiving",
"default": false,
"advanced": true
},
{
"name": "debugSending",
"type": "checkbox",
"help": "extra debugging on sending",
"default": false,
"advanced": true
},
{
"name": "clockSkew",
"label": "Clock Skew",
"help": "Number of msecs to skew the server clock by to test clock skew",
"placeholder": "0",
"default": "0",
"advanced": true
}
]
},
{
"name": "voxel_server_settings",
"label": "Voxel Server Settings",
"assignment-types": [3],
"settings": [
{
"name": "statusHost",
"label": "Status Hostname",
"help": "host name or IP address of the server for accessing the status page",
"placeholder": "",
"default": "",
"advanced": true
},
{
"name": "statusPort",
"label": "Status Port",
"help": "port of the server for accessing the status page",
"placeholder": "",
"default": "",
"advanced": true
},
{
"name": "clockSkew",
"label": "Clock Skew",
"help": "Number of msecs to skew the server clock by to test clock skew",
"placeholder": "0",
"default": "0",
"advanced": true
},
{
"name": "sendEnvironments",
"type": "checkbox",
"help": "send environmental data",
"default": false,
"advanced": true
},
{
"name": "minimalEnvironment",
"type": "checkbox",
"help": "send minimal environmental data if sending environmental data",
"default": false,
"advanced": true
}
]
}
]

164
examples/birdSongs.js Normal file
View file

@ -0,0 +1,164 @@
//
// birdSongs.js
// examples
//
// Copyright 2014 High Fidelity, Inc.
// Plays a sample audio file at the avatar's current location
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// First, load a sample sound from a URL
var birds = [];
var playing = [];
var lowerCorner = { x: 0, y: 8, z: 0 };
var upperCorner = { x: 10, y: 10, z: 10 };
var RATE = 0.035;
var numPlaying = 0;
var BIRD_SIZE = 0.1;
var BIRD_VELOCITY = 2.0;
var LIGHT_RADIUS = 10.0;
var BIRD_MASTER_VOLUME = 0.5;
var useLights = true;
function randomVector(scale) {
return { x: Math.random() * scale - scale / 2.0, y: Math.random() * scale - scale / 2.0, z: Math.random() * scale - scale / 2.0 };
}
function maybePlaySound(deltaTime) {
if (Math.random() < RATE) {
// Set the location and other info for the sound to play
var whichBird = Math.floor(Math.random() * birds.length);
//print("playing sound # " + whichBird);
var options = new AudioInjectionOptions();
var position = { x: lowerCorner.x + Math.random() * (upperCorner.x - lowerCorner.x),
y: lowerCorner.y + Math.random() * (upperCorner.y - lowerCorner.y),
z: lowerCorner.z + Math.random() * (upperCorner.z - lowerCorner.z) };
options.position = position;
options.volume = BIRD_MASTER_VOLUME;
//
var entityId = Entities.addEntity({
type: "Sphere",
position: position,
dimensions: { x: BIRD_SIZE, y: BIRD_SIZE, z: BIRD_SIZE },
color: birds[whichBird].color,
lifetime: 10
});
if (useLights) {
var lightId = Entities.addEntity({
type: "Light",
position: position,
dimensions: { x: LIGHT_RADIUS, y: LIGHT_RADIUS, z: LIGHT_RADIUS },
isSpotlight: false,
diffuseColor: birds[whichBird].color,
ambientColor: { red: 0, green: 0, blue: 0 },
specularColor: { red: 255, green: 255, blue: 255 },
constantAttenuation: 0,
linearAttenuation: 4.0,
quadraticAttenuation: 2.0,
lifetime: 10
});
}
playing.push({ audioId: Audio.playSound(birds[whichBird].sound, options), entityId: entityId, lightId: lightId, color: birds[whichBird].color });
}
if (playing.length != numPlaying) {
numPlaying = playing.length;
//print("number playing = " + numPlaying);
}
for (var i = 0; i < playing.length; i++) {
if (!Audio.isInjectorPlaying(playing[i].audioId)) {
Entities.deleteEntity(playing[i].entityId);
if (useLights) {
Entities.deleteEntity(playing[i].lightId);
}
playing.splice(i, 1);
} else {
var loudness = Audio.getLoudness(playing[i].audioId);
var newColor = { red: playing[i].color.red, green: playing[i].color.green, blue: playing[i].color.blue };
if (loudness > 0.05) {
newColor.red *= (1.0 - loudness);
newColor.green *= (1.0 - loudness);
newColor.blue *= (1.0 - loudness);
}
var properties = Entities.getEntityProperties(playing[i].entityId);
var newPosition = Vec3.sum(properties.position, randomVector(BIRD_VELOCITY * deltaTime));
if (properties) {
properties.position = newPosition;
Entities.editEntity(playing[i].entityId, { position: properties.position, color: newColor });
}
if (useLights) {
var lightProperties = Entities.getEntityProperties(playing[i].lightId);
if (lightProperties) {
Entities.editEntity(playing[i].lightId, { position: newPosition, diffuseColor: newColor });
}
}
}
}
}
loadBirds();
// Connect a call back that happens every frame
Script.update.connect(maybePlaySound);
// Delete our little friends if script is stopped
Script.scriptEnding.connect(function() {
for (var i = 0; i < playing.length; i++) {
Entities.deleteEntity(playing[i].entityId);
if (useLights) {
Entities.deleteEntity(playing[i].lightId);
}
}
});
function loadBirds() {
var sound_filenames = ["bushtit_1.raw", "bushtit_2.raw", "bushtit_3.raw", "mexicanWhipoorwill.raw",
"rosyfacedlovebird.raw", "saysphoebe.raw", "westernscreechowl.raw", "bandtailedpigeon.wav", "bridledtitmouse.wav",
"browncrestedflycatcher.wav", "commonnighthawk.wav", "commonpoorwill.wav", "doublecrestedcormorant.wav",
"gambelsquail.wav", "goldcrownedkinglet.wav", "greaterroadrunner.wav","groovebilledani.wav","hairywoodpecker.wav",
"housewren.wav","hummingbird.wav", "mountainchickadee.wav", "nightjar.wav", "piebilledgrieb.wav", "pygmynuthatch.wav",
"whistlingduck.wav", "woodpecker.wav"];
var colors = [
{ red: 242, green: 207, blue: 013 },
{ red: 238, green: 94, blue: 11 },
{ red: 81, green: 30, blue: 7 },
{ red: 195, green: 176, blue: 81 },
{ red: 235, green: 190, blue: 152 },
{ red: 167, green: 99, blue: 52 },
{ red: 199, green: 122, blue: 108 },
{ red: 246, green: 220, blue: 189 },
{ red: 208, green: 145, blue: 65 },
{ red: 173, green: 120 , blue: 71 },
{ red: 132, green: 147, blue: 174 },
{ red: 164, green: 74, blue: 40 },
{ red: 131, green: 127, blue: 134 },
{ red: 209, green: 157, blue: 117 },
{ red: 205, green: 191, blue: 193 },
{ red: 193, green: 154, blue: 118 },
{ red: 205, green: 190, blue: 169 },
{ red: 199, green: 111, blue: 69 },
{ red: 221, green: 223, blue: 228 },
{ red: 115, green: 92, blue: 87 },
{ red: 214, green: 165, blue: 137 },
{ red: 160, green: 124, blue: 33 },
{ red: 117, green: 91, blue: 86 },
{ red: 113, green: 104, blue: 107 },
{ red: 216, green: 153, blue: 99 },
{ red: 242, green: 226, blue: 64 }
];
var SOUND_BASE_URL = "http://public.highfidelity.io/sounds/Animals/";
for (var i = 0; i < sound_filenames.length; i++) {
birds.push({ sound: new Sound(SOUND_BASE_URL + sound_filenames[i]),
color: colors[i]
} );
}
}

View file

@ -12,6 +12,8 @@ var MIN_CHANGE = 2.0;
var LANDING_DISTANCE = 2.0;
var LANDING_RANDOM = 0.2;
var relativePosition;
function update(deltaTime) {
if (Math.random() < deltaTime) {
@ -26,20 +28,15 @@ function update(deltaTime) {
}
if (guide) {
relativePosition = Vec3.subtract(MyAvatar.position, lastGuidePosition);
// Check whether guide has moved, update if so
if (Vec3.length(lastGuidePosition) == 0.0) {
lastGuidePosition = guide.position;
} else {
if (Vec3.length(Vec3.subtract(lastGuidePosition, guide.position)) > MIN_CHANGE) {
var meToGuide = Vec3.multiply(Vec3.normalize(Vec3.subtract(guide.position, MyAvatar.position)), LANDING_DISTANCE);
var newPosition = Vec3.subtract(guide.position, meToGuide);
newPosition = Vec3.sum(newPosition, { x: Math.random() * LANDING_RANDOM - LANDING_RANDOM / 2.0,
y: 0,
z: Math.random() * LANDING_RANDOM - LANDING_RANDOM / 2.0 });
var newPosition = Vec3.sum(guide.position, relativePosition);
MyAvatar.position = newPosition;
lastGuidePosition = guide.position;
MyAvatar.orientation = guide.orientation;
}
}
}

46
examples/lightExample.js Normal file
View file

@ -0,0 +1,46 @@
//
// lightExample.js
// examples
//
// Created by Philip Rosedale on November 5, 2014
// Copyright 2014 High Fidelity, Inc.
//
// Makes a light right in front of your avatar, as well as a sphere at that location.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var position = Vec3.sum(MyAvatar.position, Quat.getFront(Camera.getOrientation()));
var sphereID = Entities.addEntity({
type: "Sphere",
position: position,
dimensions: { x: 0.1, y: 0.1, z: 0.1 },
color: { red: 255, green: 255, blue: 0 }
});
var lightID = Entities.addEntity({
type: "Light",
position: position,
dimensions: { x: 1, y: 1, z: 1 },
angularVelocity: { x: 0, y: 0, z: 0 },
angularDamping: 0,
isSpotlight: false,
diffuseColor: { red: 255, green: 255, blue: 0 },
ambientColor: { red: 0, green: 0, blue: 0 },
specularColor: { red: 255, green: 255, blue: 255 },
constantAttenuation: 0,
linearAttenuation: 1,
quadraticAttenuation: 0,
exponent: 0,
cutoff: 180, // in degrees
});
Script.scriptEnding.connect(function() {
print("Deleted sphere and light");
Entities.deleteEntity(sphereID);
Entities.deleteEntity(lightID);
});

View file

@ -14,5 +14,6 @@
void main(void) {
gl_Position = ftransform();
vec4 projected = gl_Position / gl_Position.w;
gl_TexCoord[0] = vec4(dot(projected, gl_ObjectPlaneS[3]), dot(projected, gl_ObjectPlaneT[3]), 0.0, 1.0);
gl_TexCoord[0] = vec4(dot(projected, gl_ObjectPlaneS[3]) * gl_Position.w,
dot(projected, gl_ObjectPlaneT[3]) * gl_Position.w, 0.0, gl_Position.w);
}

View file

@ -40,16 +40,17 @@ uniform float radius;
void main(void) {
// get the depth and exit early if it doesn't pass the test
float depth = texture2D(depthMap, gl_TexCoord[0].st).r;
vec2 texCoord = gl_TexCoord[0].st / gl_TexCoord[0].q;
float depth = texture2D(depthMap, texCoord).r;
if (depth < gl_FragCoord.z) {
discard;
}
// compute the view space position using the depth
float z = near / (depth * depthScale - 1.0);
vec4 position = vec4((depthTexCoordOffset + gl_TexCoord[0].st * depthTexCoordScale) * z, z, 1.0);
vec4 position = vec4((depthTexCoordOffset + texCoord * depthTexCoordScale) * z, z, 1.0);
// get the normal from the map
vec4 normal = texture2D(normalMap, gl_TexCoord[0].st);
vec4 normal = texture2D(normalMap, texCoord);
vec4 normalizedNormal = normalize(normal * 2.0 - vec4(1.0, 1.0, 1.0, 2.0));
// compute the base color based on OpenGL lighting model
@ -58,7 +59,7 @@ void main(void) {
lightVector = lightVector / lightDistance;
float diffuse = dot(normalizedNormal, lightVector);
float facingLight = step(0.0, diffuse);
vec4 baseColor = texture2D(diffuseMap, gl_TexCoord[0].st) * (gl_FrontLightProduct[1].ambient +
vec4 baseColor = texture2D(diffuseMap, texCoord) * (gl_FrontLightProduct[1].ambient +
gl_FrontLightProduct[1].diffuse * (diffuse * facingLight));
// compute attenuation based on distance, etc.
@ -69,6 +70,6 @@ void main(void) {
// add base to specular, modulate by attenuation
float specular = facingLight * max(0.0, dot(normalize(lightVector - normalize(vec4(position.xyz, 0.0))),
normalizedNormal));
vec4 specularColor = texture2D(specularMap, gl_TexCoord[0].st);
vec4 specularColor = texture2D(specularMap, texCoord);
gl_FragColor = vec4((baseColor.rgb + pow(specular, specularColor.a * 128.0) * specularColor.rgb) * attenuation, 0.0);
}

View file

@ -40,16 +40,17 @@ uniform float radius;
void main(void) {
// get the depth and exit early if it doesn't pass the test
float depth = texture2D(depthMap, gl_TexCoord[0].st).r;
vec2 texCoord = gl_TexCoord[0].st / gl_TexCoord[0].q;
float depth = texture2D(depthMap, texCoord).r;
if (depth < gl_FragCoord.z) {
discard;
}
// compute the view space position using the depth
float z = near / (depth * depthScale - 1.0);
vec4 position = vec4((depthTexCoordOffset + gl_TexCoord[0].st * depthTexCoordScale) * z, z, 1.0);
vec4 position = vec4((depthTexCoordOffset + texCoord * depthTexCoordScale) * z, z, 1.0);
// get the normal from the map
vec4 normal = texture2D(normalMap, gl_TexCoord[0].st);
vec4 normal = texture2D(normalMap, texCoord);
vec4 normalizedNormal = normalize(normal * 2.0 - vec4(1.0, 1.0, 1.0, 2.0));
// compute the base color based on OpenGL lighting model
@ -58,7 +59,7 @@ void main(void) {
lightVector = lightVector / lightDistance;
float diffuse = dot(normalizedNormal, lightVector);
float facingLight = step(0.0, diffuse);
vec4 baseColor = texture2D(diffuseMap, gl_TexCoord[0].st) * (gl_FrontLightProduct[1].ambient +
vec4 baseColor = texture2D(diffuseMap, texCoord) * (gl_FrontLightProduct[1].ambient +
gl_FrontLightProduct[1].diffuse * (diffuse * facingLight));
// compute attenuation based on spot angle, distance, etc.
@ -71,6 +72,6 @@ void main(void) {
// add base to specular, modulate by attenuation
float specular = facingLight * max(0.0, dot(normalize(lightVector - normalize(vec4(position.xyz, 0.0))),
normalizedNormal));
vec4 specularColor = texture2D(specularMap, gl_TexCoord[0].st);
vec4 specularColor = texture2D(specularMap, texCoord);
gl_FragColor = vec4((baseColor.rgb + pow(specular, specularColor.a * 128.0) * specularColor.rgb) * attenuation, 0.0);
}

View file

@ -81,6 +81,7 @@
#include "renderer/ProgramObject.h"
#include "gpu/Batch.h"
#include "gpu/GLBackend.h"
#include "scripting/AccountScriptingInterface.h"
#include "scripting/AudioDeviceScriptingInterface.h"

View file

@ -77,6 +77,9 @@ Audio::Audio(QObject* parent) :
_isStereoInput(false),
_averagedLatency(0.0),
_lastInputLoudness(0),
_inputFrameCounter(0),
_quietestFrame(std::numeric_limits<float>::max()),
_loudestFrame(0.0f),
_timeSinceLastClip(-1.0),
_dcOffset(0),
_noiseGateMeasuredFloor(0),
@ -717,6 +720,20 @@ void Audio::handleAudioInput() {
}
_lastInputLoudness = fabs(loudness / NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
if (_quietestFrame > _lastInputLoudness) {
_quietestFrame = _lastInputLoudness;
}
if (_loudestFrame < _lastInputLoudness) {
_loudestFrame = _lastInputLoudness;
}
const int FRAMES_FOR_NOISE_DETECTION = 400;
if (_inputFrameCounter++ > FRAMES_FOR_NOISE_DETECTION) {
_quietestFrame = std::numeric_limits<float>::max();
_loudestFrame = 0.0f;
_inputFrameCounter = 0;
}
// If Noise Gate is enabled, check and turn the gate on and off
if (!_audioSourceInjectEnabled && _noiseGateEnabled) {

View file

@ -213,6 +213,9 @@ private:
QElapsedTimer _timeSinceLastReceived;
float _averagedLatency;
float _lastInputLoudness;
int _inputFrameCounter;
float _quietestFrame;
float _loudestFrame;
float _timeSinceLastClip;
float _dcOffset;
float _noiseGateMeasuredFloor;

View file

@ -52,12 +52,10 @@ Hair::Hair(int strands,
glm::vec3 thisVertex;
for (int strand = 0; strand < _strands; strand++) {
float strandAngle = randFloat() * PI;
float azimuth;
float elevation = - (randFloat() * PI);
azimuth = PI_OVER_TWO;
if (randFloat() < 0.5f) {
azimuth *= -1.0f;
}
float azimuth = (float)strand / (float)_strands * PI * 2.0f;
float elevation = 0.0f;
glm::vec3 thisStrand(sinf(azimuth) * cosf(elevation), sinf(elevation), -cosf(azimuth) * cosf(elevation));
thisStrand *= _radius;
@ -115,11 +113,22 @@ void Hair::simulate(float deltaTime) {
glm::vec3 diff = thisPosition - _hairLastPosition[vertexIndex];
_hairPosition[vertexIndex] += diff * HAIR_DAMPING;
/*
// Resolve collisions with sphere
if (glm::length(_hairPosition[vertexIndex]) < _radius) {
_hairPosition[vertexIndex] += glm::normalize(_hairPosition[vertexIndex]) *
(_radius - glm::length(_hairPosition[vertexIndex]));
} */
// Collide with a conical body descending from the root of the hair
glm::vec3 thisVertex = _hairPosition[vertexIndex];
float depth = -thisVertex.y;
thisVertex.y = 0.0f;
const float BODY_CONE_ANGLE = 0.30;
if (glm::length(thisVertex) < depth * BODY_CONE_ANGLE) {
_hairPosition[vertexIndex] += glm::normalize(thisVertex) * (depth * BODY_CONE_ANGLE - glm::length(thisVertex));
}
// Add random thing driven by loudness
float loudnessFactor = (_loudness > SOUND_THRESHOLD) ? logf(_loudness - SOUND_THRESHOLD) / 2000.0f : 0.0f;

View file

@ -12,7 +12,6 @@
#include <QDebug>
//#define ADD_COMMAND(call) _commands.push_back(COMMAND_##call); _commandCalls.push_back(&gpu::Batch::do_##call); _commandOffsets.push_back(_params.size());
#define ADD_COMMAND(call) _commands.push_back(COMMAND_##call); _commandOffsets.push_back(_params.size());
using namespace gpu;
@ -33,6 +32,7 @@ void Batch::clear() {
_commandOffsets.clear();
_params.clear();
_resources.clear();
_buffers.clear();
_data.clear();
}
@ -59,7 +59,7 @@ uint32 Batch::cacheData(uint32 size, const void* data) {
return offset;
}
void Batch::draw(Primitive primitiveType, int nbVertices, int startVertex) {
void Batch::draw(Primitive primitiveType, uint32 nbVertices, uint32 startVertex) {
ADD_COMMAND(draw);
_params.push_back(startVertex);
@ -67,7 +67,7 @@ void Batch::draw(Primitive primitiveType, int nbVertices, int startVertex) {
_params.push_back(primitiveType);
}
void Batch::drawIndexed(Primitive primitiveType, int nbIndices, int startIndex) {
void Batch::drawIndexed(Primitive primitiveType, uint32 nbIndices, uint32 startIndex) {
ADD_COMMAND(drawIndexed);
_params.push_back(startIndex);
@ -75,7 +75,7 @@ void Batch::drawIndexed(Primitive primitiveType, int nbIndices, int startIndex)
_params.push_back(primitiveType);
}
void Batch::drawInstanced(uint32 nbInstances, Primitive primitiveType, int nbVertices, int startVertex, int startInstance) {
void Batch::drawInstanced(uint32 nbInstances, Primitive primitiveType, uint32 nbVertices, uint32 startVertex, uint32 startInstance) {
ADD_COMMAND(drawInstanced);
_params.push_back(startInstance);
@ -85,7 +85,7 @@ void Batch::drawInstanced(uint32 nbInstances, Primitive primitiveType, int nbVer
_params.push_back(nbInstances);
}
void Batch::drawIndexedInstanced(uint32 nbInstances, Primitive primitiveType, int nbIndices, int startIndex, int startInstance) {
void Batch::drawIndexedInstanced(uint32 nbInstances, Primitive primitiveType, uint32 nbIndices, uint32 startIndex, uint32 startInstance) {
ADD_COMMAND(drawIndexedInstanced);
_params.push_back(startInstance);
@ -95,5 +95,36 @@ void Batch::drawIndexedInstanced(uint32 nbInstances, Primitive primitiveType, in
_params.push_back(nbInstances);
}
void Batch::setInputFormat(const Stream::FormatPointer& format) {
ADD_COMMAND(setInputFormat);
_params.push_back(_streamFormats.cache(format));
}
void Batch::setInputStream(Slot startChannel, const BufferStream& stream) {
if (stream.getNumBuffers()) {
const Buffers& buffers = stream.getBuffers();
const Offsets& offsets = stream.getOffsets();
const Offsets& strides = stream.getStrides();
for (int i = 0; i < buffers.size(); i++) {
setInputBuffer(startChannel + i, buffers[i], offsets[i], strides[i]);
}
}
}
void Batch::setInputBuffer(Slot channel, const BufferPointer& buffer, Offset offset, Offset stride) {
ADD_COMMAND(setInputBuffer);
_params.push_back(stride);
_params.push_back(offset);
_params.push_back(_buffers.cache(buffer));
_params.push_back(channel);
}
void Batch::setIndexBuffer(Type type, const BufferPointer& buffer, Offset offset) {
ADD_COMMAND(setIndexBuffer);
_params.push_back(offset);
_params.push_back(_buffers.cache(buffer));
_params.push_back(type);
}

View file

@ -16,6 +16,10 @@
#include <vector>
#include "gpu/Format.h"
#include "gpu/Resource.h"
#include "gpu/Stream.h"
#if defined(NSIGHT_FOUND)
#include "nvToolsExt.h"
class ProfileRange {
@ -35,23 +39,20 @@
namespace gpu {
class Buffer;
class Resource;
typedef int Stamp;
typedef unsigned int uint32;
typedef int int32;
enum Primitive {
PRIMITIVE_POINTS = 0,
PRIMITIVE_LINES,
PRIMITIVE_LINE_STRIP,
PRIMITIVE_TRIANGLES,
PRIMITIVE_TRIANGLE_STRIP,
PRIMITIVE_QUADS,
POINTS = 0,
LINES,
LINE_STRIP,
TRIANGLES,
TRIANGLE_STRIP,
QUADS,
NUM_PRIMITIVES,
};
class Batch {
public:
typedef Stream::Slot Slot;
Batch();
Batch(const Batch& batch);
@ -59,10 +60,18 @@ public:
void clear();
void draw(Primitive primitiveType, int nbVertices, int startVertex = 0);
void drawIndexed(Primitive primitiveType, int nbIndices, int startIndex = 0);
void drawInstanced(uint32 nbInstances, Primitive primitiveType, int nbVertices, int startVertex = 0, int startInstance = 0);
void drawIndexedInstanced(uint32 nbInstances, Primitive primitiveType, int nbIndices, int startIndex = 0, int startInstance = 0);
void draw(Primitive primitiveType, uint32 numVertices, uint32 startVertex = 0);
void drawIndexed(Primitive primitiveType, uint32 nbIndices, uint32 startIndex = 0);
void drawInstanced(uint32 nbInstances, Primitive primitiveType, uint32 nbVertices, uint32 startVertex = 0, uint32 startInstance = 0);
void drawIndexedInstanced(uint32 nbInstances, Primitive primitiveType, uint32 nbIndices, uint32 startIndex = 0, uint32 startInstance = 0);
void setInputFormat(const Stream::FormatPointer& format);
void setInputStream(Slot startChannel, const BufferStream& stream); // not a command, just unroll into a loop of setInputBuffer
void setInputBuffer(Slot channel, const BufferPointer& buffer, Offset offset, Offset stride);
void setIndexBuffer(Type type, const BufferPointer& buffer, Offset offset);
// TODO: As long as we have gl calls explicitely issued from interface
// code, we need to be able to record and batch these calls. THe long
@ -127,13 +136,12 @@ public:
COMMAND_drawIndexed,
COMMAND_drawInstanced,
COMMAND_drawIndexedInstanced,
COMMAND_SET_PIPE_STATE,
COMMAND_SET_VIEWPORT,
COMMAND_SET_FRAMEBUFFER,
COMMAND_SET_RESOURCE,
COMMAND_SET_VERTEX_STREAM,
COMMAND_SET_INDEX_STREAM,
COMMAND_setInputFormat,
COMMAND_setInputBuffer,
COMMAND_setIndexBuffer,
// TODO: As long as we have gl calls explicitely issued from interface
// code, we need to be able to record and batch these calls. THe long
@ -226,21 +234,64 @@ public:
};
typedef std::vector<ResourceCache> Resources;
template <typename T>
class Cache {
public:
typedef QSharedPointer<T> Pointer;
Pointer _pointer;
Cache<T>(const Pointer& pointer) : _pointer(pointer) {}
class Vector {
public:
std::vector< Cache<T> > _pointers;
uint32 cache(const Pointer& pointer) {
uint32 offset = _pointers.size();
_pointers.push_back(Cache<T>(pointer));
return offset;
}
Pointer get(uint32 offset) {
if (offset >= _pointers.size()) {
return Pointer();
}
return (_pointers.data() + offset)->_pointer;
}
void clear() {
_pointers.clear();
}
};
};
typedef Cache<Buffer>::Vector BufferCaches;
typedef Cache<Stream::Format>::Vector StreamFormatCaches;
typedef unsigned char Byte;
typedef std::vector<Byte> Bytes;
uint32 cacheResource(Resource* res);
uint32 cacheResource(const void* pointer);
ResourceCache* editResource(uint32 offset) {
if (offset >= _resources.size())
if (offset >= _resources.size()) {
return 0;
}
return (_resources.data() + offset);
}
template <typename T>
T* editResourcePointer(uint32 offset) {
if (offset >= _resources.size()) {
return 0;
}
return reinterpret_cast<T*>((_resources.data() + offset)->_pointer);
}
uint32 cacheData(uint32 size, const void* data);
Byte* editData(uint32 offset) {
if (offset >= _data.size())
if (offset >= _data.size()) {
return 0;
}
return (_data.data() + offset);
}
@ -248,6 +299,10 @@ public:
CommandOffsets _commandOffsets;
Params _params;
Resources _resources;
BufferCaches _buffers;
StreamFormatCaches _streamFormats;
Bytes _data;
protected:
};

147
interface/src/gpu/Format.h Normal file
View file

@ -0,0 +1,147 @@
//
// Format.h
// interface/src/gpu
//
// Created by Sam Gateau on 10/29/2014.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_gpu_Format_h
#define hifi_gpu_Format_h
#include <assert.h>
#include "InterfaceConfig.h"
namespace gpu {
typedef unsigned int uint32;
typedef int int32;
typedef unsigned short uint16;
typedef short int16;
typedef unsigned char uint8;
typedef char int8;
typedef uint32 Offset;
// Description of a scalar type
enum Type {
FLOAT = 0,
INT32,
UINT32,
HALF,
INT16,
UINT16,
INT8,
UINT8,
NFLOAT,
NINT32,
NUINT32,
NHALF,
NINT16,
NUINT16,
NINT8,
NUINT8,
NUM_TYPES,
};
// Array providing the size in bytes for a given scalar type
static const int TYPE_SIZE[NUM_TYPES] = {
4,
4,
4,
2,
2,
2,
1,
1,
4,
4,
4,
2,
2,
2,
1,
1
};
// Dimension of an Element
enum Dimension {
SCALAR = 0,
VEC2,
VEC3,
VEC4,
MAT3,
MAT4,
NUM_DIMENSIONS,
};
// Count (of scalars) in an Element for a given Dimension
static const int DIMENSION_COUNT[NUM_DIMENSIONS] = {
1,
2,
3,
4,
9,
16
};
// Semantic of an Element
// Provide information on how to use the element
enum Semantic {
RGB = 0,
RGBA,
XYZ,
XYZW,
POS_XYZ,
POS_XYZW,
QUAT,
DIR_XYZ,
UV,
R8,
NUM_SEMANTICS,
};
// Element is a simple 16bit value that contains everything we need to know about an element
// of a buffer, a pixel of a texture, a varying input/output or uniform from a shader pipeline.
// Type and dimension of the element, and semantic
class Element {
public:
Element(Dimension dim, Type type, Semantic sem) :
_semantic(sem),
_dimension(dim),
_type(type)
{}
Element() :
_semantic(R8),
_dimension(SCALAR),
_type(INT8)
{}
Semantic getSemantic() const { return (Semantic)_semantic; }
Dimension getDimension() const { return (Dimension)_dimension; }
uint8 getDimensionCount() const { return DIMENSION_COUNT[(Dimension)_dimension]; }
Type getType() const { return (Type)_type; }
bool isNormalized() const { return (getType() >= NFLOAT); }
uint32 getSize() const { return DIMENSION_COUNT[_dimension] * TYPE_SIZE[_type]; }
protected:
uint8 _semantic;
uint8 _dimension : 4;
uint8 _type : 4;
};
};
#endif

View file

@ -18,6 +18,17 @@ using namespace gpu;
GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
{
(&::gpu::GLBackend::do_draw),
(&::gpu::GLBackend::do_drawIndexed),
(&::gpu::GLBackend::do_drawInstanced),
(&::gpu::GLBackend::do_drawIndexedInstanced),
(&::gpu::GLBackend::do_setInputFormat),
(&::gpu::GLBackend::do_setInputBuffer),
(&::gpu::GLBackend::do_setIndexBuffer),
(&::gpu::GLBackend::do_glEnable),
(&::gpu::GLBackend::do_glDisable),
@ -70,8 +81,49 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
(&::gpu::GLBackend::do_glMaterialfv),
};
static const GLenum _primitiveToGLmode[NUM_PRIMITIVES] = {
GL_POINTS,
GL_LINES,
GL_LINE_STRIP,
GL_TRIANGLES,
GL_TRIANGLE_STRIP,
GL_QUADS,
};
GLBackend::GLBackend() {
static const GLenum _elementTypeToGLType[NUM_TYPES]= {
GL_FLOAT,
GL_INT,
GL_UNSIGNED_INT,
GL_HALF_FLOAT,
GL_SHORT,
GL_UNSIGNED_SHORT,
GL_BYTE,
GL_UNSIGNED_BYTE,
GL_FLOAT,
GL_INT,
GL_UNSIGNED_INT,
GL_HALF_FLOAT,
GL_SHORT,
GL_UNSIGNED_SHORT,
GL_BYTE,
GL_UNSIGNED_BYTE
};
GLBackend::GLBackend() :
_inputFormat(0),
_inputAttributeActivation(0),
_needInputFormatUpdate(true),
_inputBuffersState(0),
_inputBuffers(_inputBuffersState.size(), BufferPointer(0)),
_inputBufferOffsets(_inputBuffersState.size(), 0),
_inputBufferStrides(_inputBuffersState.size(), 0),
_indexBuffer(0),
_indexBufferOffset(0)
{
}
@ -87,7 +139,7 @@ void GLBackend::renderBatch(Batch& batch) {
GLBackend backend;
for (int i = 0; i < numCommands; i++) {
CommandCall call = _commandCalls[((*command) - Batch::COMMAND_glEnable)];
CommandCall call = _commandCalls[(*command)];
(backend.*(call))(batch, *offset);
command++;
offset++;
@ -126,24 +178,264 @@ void GLBackend::checkGLError() {
}
}
//#define CHECK_GL_ERROR() ::gpu::GLBackend::checkGLError()
#define CHECK_GL_ERROR()
void GLBackend::do_draw(Batch& batch, uint32 paramOffset) {
updateInput();
Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint;
GLenum mode = _primitiveToGLmode[primitiveType];
uint32 numVertices = batch._params[paramOffset + 1]._uint;
uint32 startVertex = batch._params[paramOffset + 0]._uint;
glDrawArrays(mode, startVertex, numVertices);
CHECK_GL_ERROR();
}
void GLBackend::do_drawIndexed(Batch& batch, uint32 paramOffset) {
updateInput();
Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint;
GLenum mode = _primitiveToGLmode[primitiveType];
uint32 numIndices = batch._params[paramOffset + 1]._uint;
uint32 startIndex = batch._params[paramOffset + 0]._uint;
GLenum glType = _elementTypeToGLType[_indexBufferType];
glDrawElements(mode, numIndices, glType, (GLvoid*)(startIndex + _indexBufferOffset));
CHECK_GL_ERROR();
}
void GLBackend::do_drawInstanced(Batch& batch, uint32 paramOffset) {
CHECK_GL_ERROR();
}
void GLBackend::do_drawIndexedInstanced(Batch& batch, uint32 paramOffset) {
CHECK_GL_ERROR();
}
void GLBackend::do_setInputFormat(Batch& batch, uint32 paramOffset) {
Stream::FormatPointer format = batch._streamFormats.get(batch._params[paramOffset]._uint);
if (format != _inputFormat) {
_inputFormat = format;
_needInputFormatUpdate = true;
}
}
void GLBackend::do_setInputBuffer(Batch& batch, uint32 paramOffset) {
Offset stride = batch._params[paramOffset + 0]._uint;
Offset offset = batch._params[paramOffset + 1]._uint;
BufferPointer buffer = batch._buffers.get(batch._params[paramOffset + 2]._uint);
uint32 channel = batch._params[paramOffset + 3]._uint;
if (channel < getNumInputBuffers()) {
_inputBuffers[channel] = buffer;
_inputBufferOffsets[channel] = offset;
_inputBufferStrides[channel] = stride;
_inputBuffersState.set(channel);
}
}
#define SUPPORT_LEGACY_OPENGL
#if defined(SUPPORT_LEGACY_OPENGL)
static const int NUM_CLASSIC_ATTRIBS = Stream::TANGENT;
static const GLenum attributeSlotToClassicAttribName[NUM_CLASSIC_ATTRIBS] = {
GL_VERTEX_ARRAY,
GL_NORMAL_ARRAY,
GL_COLOR_ARRAY,
GL_TEXTURE_COORD_ARRAY
};
#endif
void GLBackend::updateInput() {
if (_needInputFormatUpdate || _inputBuffersState.any()) {
if (_needInputFormatUpdate) {
InputActivationCache newActivation;
// Check expected activation
if (_inputFormat) {
const Stream::Format::AttributeMap& attributes = _inputFormat->getAttributes();
for (Stream::Format::AttributeMap::const_iterator it = attributes.begin(); it != attributes.end(); it++) {
const Stream::Attribute& attrib = (*it).second;
newActivation.set(attrib._slot);
}
}
// Manage Activation what was and what is expected now
for (int i = 0; i < newActivation.size(); i++) {
bool newState = newActivation[i];
if (newState != _inputAttributeActivation[i]) {
#if defined(SUPPORT_LEGACY_OPENGL)
if (i < NUM_CLASSIC_ATTRIBS) {
if (newState) {
glEnableClientState(attributeSlotToClassicAttribName[i]);
}
else {
glDisableClientState(attributeSlotToClassicAttribName[i]);
}
} else {
#else
{
#endif
if (newState) {
glEnableVertexAttribArray(i);
} else {
glDisableVertexAttribArray(i);
}
}
CHECK_GL_ERROR();
_inputAttributeActivation.flip(i);
}
}
}
// now we need to bind the buffers and assign the attrib pointers
if (_inputFormat) {
const Buffers& buffers = _inputBuffers;
const Offsets& offsets = _inputBufferOffsets;
const Offsets& strides = _inputBufferStrides;
const Stream::Format::AttributeMap& attributes = _inputFormat->getAttributes();
for (Stream::Format::ChannelMap::const_iterator channelIt = _inputFormat->getChannels().begin();
channelIt != _inputFormat->getChannels().end();
channelIt++) {
const Stream::Format::ChannelMap::value_type::second_type& channel = (*channelIt).second;
if ((*channelIt).first < buffers.size()) {
int bufferNum = (*channelIt).first;
if (_inputBuffersState.test(bufferNum) || _needInputFormatUpdate) {
GLuint vbo = gpu::GLBackend::getBufferID((*buffers[bufferNum]));
glBindBuffer(GL_ARRAY_BUFFER, vbo);
CHECK_GL_ERROR();
_inputBuffersState[bufferNum] = false;
for (int i = 0; i < channel._slots.size(); i++) {
const Stream::Attribute& attrib = attributes.at(channel._slots[i]);
GLuint slot = attrib._slot;
GLuint count = attrib._element.getDimensionCount();
GLenum type = _elementTypeToGLType[attrib._element.getType()];
GLuint stride = strides[bufferNum];
GLuint pointer = attrib._offset + offsets[bufferNum];
#if defined(SUPPORT_LEGACY_OPENGL)
if (slot < NUM_CLASSIC_ATTRIBS) {
switch (slot) {
case Stream::POSITION:
glVertexPointer(count, type, stride, (GLvoid*)pointer);
break;
case Stream::NORMAL:
glNormalPointer(type, stride, (GLvoid*)pointer);
break;
case Stream::COLOR:
glColorPointer(count, type, stride, (GLvoid*)pointer);
break;
case Stream::TEXCOORD:
glTexCoordPointer(count, type, stride, (GLvoid*)pointer);
break;
};
} else {
#else
{
#endif
GLboolean isNormalized = attrib._element.isNormalized();
glVertexAttribPointer(slot, count, type, isNormalized, stride, (GLvoid*)pointer);
}
CHECK_GL_ERROR();
}
}
}
}
}
// everything format related should be in sync now
_needInputFormatUpdate = false;
}
/* TODO: Fancy version GL4.4
if (_needInputFormatUpdate) {
InputActivationCache newActivation;
// Assign the vertex format required
if (_inputFormat) {
const StreamFormat::AttributeMap& attributes = _inputFormat->getAttributes();
for (StreamFormat::AttributeMap::const_iterator it = attributes.begin(); it != attributes.end(); it++) {
const StreamFormat::Attribute& attrib = (*it).second;
newActivation.set(attrib._slot);
glVertexAttribFormat(
attrib._slot,
attrib._element.getDimensionCount(),
_elementTypeToGLType[attrib._element.getType()],
attrib._element.isNormalized(),
attrib._stride);
}
CHECK_GL_ERROR();
}
// Manage Activation what was and what is expected now
for (int i = 0; i < newActivation.size(); i++) {
bool newState = newActivation[i];
if (newState != _inputAttributeActivation[i]) {
if (newState) {
glEnableVertexAttribArray(i);
} else {
glDisableVertexAttribArray(i);
}
_inputAttributeActivation.flip(i);
}
}
CHECK_GL_ERROR();
_needInputFormatUpdate = false;
}
if (_needInputStreamUpdate) {
if (_inputStream) {
const Stream::Buffers& buffers = _inputStream->getBuffers();
const Stream::Offsets& offsets = _inputStream->getOffsets();
const Stream::Strides& strides = _inputStream->getStrides();
for (int i = 0; i < buffers.size(); i++) {
GLuint vbo = gpu::GLBackend::getBufferID((*buffers[i]));
glBindVertexBuffer(i, vbo, offsets[i], strides[i]);
}
CHECK_GL_ERROR();
}
_needInputStreamUpdate = false;
}
*/
}
void GLBackend::do_setIndexBuffer(Batch& batch, uint32 paramOffset) {
_indexBufferType = (Type) batch._params[paramOffset + 2]._uint;
BufferPointer indexBuffer = batch._buffers.get(batch._params[paramOffset + 1]._uint);
_indexBufferOffset = batch._params[paramOffset + 0]._uint;
_indexBuffer = indexBuffer;
if (indexBuffer) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, getBufferID(*indexBuffer));
} else {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
CHECK_GL_ERROR();
}
// TODO: As long as we have gl calls explicitely issued from interface
// code, we need to be able to record and batch these calls. THe long
// term strategy is to get rid of any GL calls in favor of the HIFI GPU API
//#define ADD_COMMAND(call) _commands.push_back(COMMAND_##call); _commandCalls.push_back(&gpu::Batch::do_##call); _commandOffsets.push_back(_params.size());
#define ADD_COMMAND(call) _commands.push_back(COMMAND_##call); _commandOffsets.push_back(_params.size());
//#define ADD_COMMAND_GL(call) _commands.push_back(COMMAND_##call); _commandCalls.push_back(&gpu::GLBackend::do_##call); _commandOffsets.push_back(_params.size());
#define ADD_COMMAND_GL(call) _commands.push_back(COMMAND_##call); _commandOffsets.push_back(_params.size());
//#define DO_IT_NOW(call, offset) runLastCommand();
#define DO_IT_NOW(call, offset)
//#define CHECK_GL_ERROR() ::gpu::backend::checkGLError()
#define CHECK_GL_ERROR()
void Batch::_glEnable(GLenum cap) {
ADD_COMMAND(glEnable);
ADD_COMMAND_GL(glEnable);
_params.push_back(cap);
@ -155,7 +447,7 @@ void GLBackend::do_glEnable(Batch& batch, uint32 paramOffset) {
}
void Batch::_glDisable(GLenum cap) {
ADD_COMMAND(glDisable);
ADD_COMMAND_GL(glDisable);
_params.push_back(cap);
@ -167,7 +459,7 @@ void GLBackend::do_glDisable(Batch& batch, uint32 paramOffset) {
}
void Batch::_glEnableClientState(GLenum array) {
ADD_COMMAND(glEnableClientState);
ADD_COMMAND_GL(glEnableClientState);
_params.push_back(array);
@ -179,7 +471,7 @@ void GLBackend::do_glEnableClientState(Batch& batch, uint32 paramOffset) {
}
void Batch::_glDisableClientState(GLenum array) {
ADD_COMMAND(glDisableClientState);
ADD_COMMAND_GL(glDisableClientState);
_params.push_back(array);
@ -191,7 +483,7 @@ void GLBackend::do_glDisableClientState(Batch& batch, uint32 paramOffset) {
}
void Batch::_glCullFace(GLenum mode) {
ADD_COMMAND(glCullFace);
ADD_COMMAND_GL(glCullFace);
_params.push_back(mode);
@ -203,7 +495,7 @@ void GLBackend::do_glCullFace(Batch& batch, uint32 paramOffset) {
}
void Batch::_glAlphaFunc(GLenum func, GLclampf ref) {
ADD_COMMAND(glAlphaFunc);
ADD_COMMAND_GL(glAlphaFunc);
_params.push_back(ref);
_params.push_back(func);
@ -218,7 +510,7 @@ void GLBackend::do_glAlphaFunc(Batch& batch, uint32 paramOffset) {
}
void Batch::_glDepthFunc(GLenum func) {
ADD_COMMAND(glDepthFunc);
ADD_COMMAND_GL(glDepthFunc);
_params.push_back(func);
@ -230,7 +522,7 @@ void GLBackend::do_glDepthFunc(Batch& batch, uint32 paramOffset) {
}
void Batch::_glDepthMask(GLboolean flag) {
ADD_COMMAND(glDepthMask);
ADD_COMMAND_GL(glDepthMask);
_params.push_back(flag);
@ -242,7 +534,7 @@ void GLBackend::do_glDepthMask(Batch& batch, uint32 paramOffset) {
}
void Batch::_glDepthRange(GLclampd zNear, GLclampd zFar) {
ADD_COMMAND(glDepthRange);
ADD_COMMAND_GL(glDepthRange);
_params.push_back(zFar);
_params.push_back(zNear);
@ -257,7 +549,7 @@ void GLBackend::do_glDepthRange(Batch& batch, uint32 paramOffset) {
}
void Batch::_glBindBuffer(GLenum target, GLuint buffer) {
ADD_COMMAND(glBindBuffer);
ADD_COMMAND_GL(glBindBuffer);
_params.push_back(buffer);
_params.push_back(target);
@ -272,7 +564,7 @@ void GLBackend::do_glBindBuffer(Batch& batch, uint32 paramOffset) {
}
void Batch::_glBindTexture(GLenum target, GLuint texture) {
ADD_COMMAND(glBindTexture);
ADD_COMMAND_GL(glBindTexture);
_params.push_back(texture);
_params.push_back(target);
@ -287,7 +579,7 @@ void GLBackend::do_glBindTexture(Batch& batch, uint32 paramOffset) {
}
void Batch::_glActiveTexture(GLenum texture) {
ADD_COMMAND(glActiveTexture);
ADD_COMMAND_GL(glActiveTexture);
_params.push_back(texture);
@ -299,7 +591,7 @@ void GLBackend::do_glActiveTexture(Batch& batch, uint32 paramOffset) {
}
void Batch::_glDrawBuffers(GLsizei n, const GLenum* bufs) {
ADD_COMMAND(glDrawBuffers);
ADD_COMMAND_GL(glDrawBuffers);
_params.push_back(cacheData(n * sizeof(GLenum), bufs));
_params.push_back(n);
@ -314,7 +606,7 @@ void GLBackend::do_glDrawBuffers(Batch& batch, uint32 paramOffset) {
}
void Batch::_glUseProgram(GLuint program) {
ADD_COMMAND(glUseProgram);
ADD_COMMAND_GL(glUseProgram);
_params.push_back(program);
@ -326,7 +618,7 @@ void GLBackend::do_glUseProgram(Batch& batch, uint32 paramOffset) {
}
void Batch::_glUniform1f(GLint location, GLfloat v0) {
ADD_COMMAND(glUniform1f);
ADD_COMMAND_GL(glUniform1f);
_params.push_back(v0);
_params.push_back(location);
@ -341,7 +633,7 @@ void GLBackend::do_glUniform1f(Batch& batch, uint32 paramOffset) {
}
void Batch::_glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
ADD_COMMAND(glUniformMatrix4fv);
ADD_COMMAND_GL(glUniformMatrix4fv);
const int MATRIX4_SIZE = 16 * sizeof(float);
_params.push_back(cacheData(count * MATRIX4_SIZE, value));
@ -361,7 +653,7 @@ void GLBackend::do_glUniformMatrix4fv(Batch& batch, uint32 paramOffset) {
}
void Batch::_glMatrixMode(GLenum mode) {
ADD_COMMAND(glMatrixMode);
ADD_COMMAND_GL(glMatrixMode);
_params.push_back(mode);
@ -373,7 +665,7 @@ void GLBackend::do_glMatrixMode(Batch& batch, uint32 paramOffset) {
}
void Batch::_glPushMatrix() {
ADD_COMMAND(glPushMatrix);
ADD_COMMAND_GL(glPushMatrix);
DO_IT_NOW(_glPushMatrix, 0);
}
@ -383,7 +675,7 @@ void GLBackend::do_glPushMatrix(Batch& batch, uint32 paramOffset) {
}
void Batch::_glPopMatrix() {
ADD_COMMAND(glPopMatrix);
ADD_COMMAND_GL(glPopMatrix);
DO_IT_NOW(_glPopMatrix, 0);
}
@ -393,7 +685,7 @@ void GLBackend::do_glPopMatrix(Batch& batch, uint32 paramOffset) {
}
void Batch::_glMultMatrixf(const GLfloat *m) {
ADD_COMMAND(glMultMatrixf);
ADD_COMMAND_GL(glMultMatrixf);
const int MATRIX4_SIZE = 16 * sizeof(float);
_params.push_back(cacheData(MATRIX4_SIZE, m));
@ -406,7 +698,7 @@ void GLBackend::do_glMultMatrixf(Batch& batch, uint32 paramOffset) {
}
void Batch::_glLoadMatrixf(const GLfloat *m) {
ADD_COMMAND(glLoadMatrixf);
ADD_COMMAND_GL(glLoadMatrixf);
const int MATRIX4_SIZE = 16 * sizeof(float);
_params.push_back(cacheData(MATRIX4_SIZE, m));
@ -419,7 +711,7 @@ void GLBackend::do_glLoadMatrixf(Batch& batch, uint32 paramOffset) {
}
void Batch::_glLoadIdentity(void) {
ADD_COMMAND(glLoadIdentity);
ADD_COMMAND_GL(glLoadIdentity);
DO_IT_NOW(_glLoadIdentity, 0);
}
@ -429,7 +721,7 @@ void GLBackend::do_glLoadIdentity(Batch& batch, uint32 paramOffset) {
}
void Batch::_glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) {
ADD_COMMAND(glRotatef);
ADD_COMMAND_GL(glRotatef);
_params.push_back(z);
_params.push_back(y);
@ -448,7 +740,7 @@ void GLBackend::do_glRotatef(Batch& batch, uint32 paramOffset) {
}
void Batch::_glScalef(GLfloat x, GLfloat y, GLfloat z) {
ADD_COMMAND(glScalef);
ADD_COMMAND_GL(glScalef);
_params.push_back(z);
_params.push_back(y);
@ -465,7 +757,7 @@ void GLBackend::do_glScalef(Batch& batch, uint32 paramOffset) {
}
void Batch::_glTranslatef(GLfloat x, GLfloat y, GLfloat z) {
ADD_COMMAND(glTranslatef);
ADD_COMMAND_GL(glTranslatef);
_params.push_back(z);
_params.push_back(y);
@ -482,7 +774,7 @@ void GLBackend::do_glTranslatef(Batch& batch, uint32 paramOffset) {
}
void Batch::_glDrawArrays(GLenum mode, GLint first, GLsizei count) {
ADD_COMMAND(glDrawArrays);
ADD_COMMAND_GL(glDrawArrays);
_params.push_back(count);
_params.push_back(first);
@ -499,7 +791,7 @@ void GLBackend::do_glDrawArrays(Batch& batch, uint32 paramOffset) {
}
void Batch::_glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices) {
ADD_COMMAND(glDrawRangeElements);
ADD_COMMAND_GL(glDrawRangeElements);
_params.push_back(cacheResource(indices));
_params.push_back(type);
@ -522,7 +814,7 @@ void GLBackend::do_glDrawRangeElements(Batch& batch, uint32 paramOffset) {
}
void Batch::_glColorPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) {
ADD_COMMAND(glColorPointer);
ADD_COMMAND_GL(glColorPointer);
_params.push_back(cacheResource(pointer));
_params.push_back(stride);
@ -541,7 +833,7 @@ void GLBackend::do_glColorPointer(Batch& batch, uint32 paramOffset) {
}
void Batch::_glNormalPointer(GLenum type, GLsizei stride, const void *pointer) {
ADD_COMMAND(glNormalPointer);
ADD_COMMAND_GL(glNormalPointer);
_params.push_back(cacheResource(pointer));
_params.push_back(stride);
@ -558,7 +850,7 @@ void GLBackend::do_glNormalPointer(Batch& batch, uint32 paramOffset) {
}
void Batch::_glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) {
ADD_COMMAND(glTexCoordPointer);
ADD_COMMAND_GL(glTexCoordPointer);
_params.push_back(cacheResource(pointer));
_params.push_back(stride);
@ -577,7 +869,7 @@ void GLBackend::do_glTexCoordPointer(Batch& batch, uint32 paramOffset) {
}
void Batch::_glVertexPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) {
ADD_COMMAND(glVertexPointer);
ADD_COMMAND_GL(glVertexPointer);
_params.push_back(cacheResource(pointer));
_params.push_back(stride);
@ -597,7 +889,7 @@ void GLBackend::do_glVertexPointer(Batch& batch, uint32 paramOffset) {
void Batch::_glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer) {
ADD_COMMAND(glVertexAttribPointer);
ADD_COMMAND_GL(glVertexAttribPointer);
_params.push_back(cacheResource(pointer));
_params.push_back(stride);
@ -620,7 +912,7 @@ void GLBackend::do_glVertexAttribPointer(Batch& batch, uint32 paramOffset) {
}
void Batch::_glEnableVertexAttribArray(GLint location) {
ADD_COMMAND(glEnableVertexAttribArray);
ADD_COMMAND_GL(glEnableVertexAttribArray);
_params.push_back(location);
@ -632,7 +924,7 @@ void GLBackend::do_glEnableVertexAttribArray(Batch& batch, uint32 paramOffset) {
}
void Batch::_glDisableVertexAttribArray(GLint location) {
ADD_COMMAND(glDisableVertexAttribArray);
ADD_COMMAND_GL(glDisableVertexAttribArray);
_params.push_back(location);
@ -644,7 +936,7 @@ void GLBackend::do_glDisableVertexAttribArray(Batch& batch, uint32 paramOffset)
}
void Batch::_glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
ADD_COMMAND(glColor4f);
ADD_COMMAND_GL(glColor4f);
_params.push_back(alpha);
_params.push_back(blue);
@ -663,7 +955,7 @@ void GLBackend::do_glColor4f(Batch& batch, uint32 paramOffset) {
}
void Batch::_glMaterialf(GLenum face, GLenum pname, GLfloat param) {
ADD_COMMAND(glMaterialf);
ADD_COMMAND_GL(glMaterialf);
_params.push_back(param);
_params.push_back(pname);
@ -680,7 +972,7 @@ void GLBackend::do_glMaterialf(Batch& batch, uint32 paramOffset) {
}
void Batch::_glMaterialfv(GLenum face, GLenum pname, const GLfloat *params) {
ADD_COMMAND(glMaterialfv);
ADD_COMMAND_GL(glMaterialfv);
_params.push_back(cacheData(4 * sizeof(float), params));
_params.push_back(pname);
@ -719,6 +1011,7 @@ void GLBackend::syncGPUObject(const Buffer& buffer) {
if (!object) {
object = new GLBuffer();
glGenBuffers(1, &object->_buffer);
CHECK_GL_ERROR();
Backend::setGPUObject(buffer, object);
}
@ -731,6 +1024,7 @@ void GLBackend::syncGPUObject(const Buffer& buffer) {
object->_stamp = buffer.getSysmem().getStamp();
object->_size = buffer.getSysmem().getSize();
//}
CHECK_GL_ERROR();
}

View file

@ -16,6 +16,8 @@
#include "gpu/Context.h"
#include "gpu/Batch.h"
#include <bitset>
namespace gpu {
@ -43,8 +45,42 @@ public:
static GLuint getBufferID(const Buffer& buffer);
static const int MAX_NUM_ATTRIBUTES = Stream::NUM_INPUT_SLOTS;
static const int MAX_NUM_INPUT_BUFFERS = 16;
uint32 getNumInputBuffers() const { return _inputBuffersState.size(); }
protected:
bool _needInputFormatUpdate;
Stream::FormatPointer _inputFormat;
typedef std::bitset<MAX_NUM_INPUT_BUFFERS> InputBuffersState;
InputBuffersState _inputBuffersState;
Buffers _inputBuffers;
Offsets _inputBufferOffsets;
Offsets _inputBufferStrides;
BufferPointer _indexBuffer;
Offset _indexBufferOffset;
Type _indexBufferType;
typedef std::bitset<MAX_NUM_ATTRIBUTES> InputActivationCache;
InputActivationCache _inputAttributeActivation;
void do_draw(Batch& batch, uint32 paramOffset);
void do_drawIndexed(Batch& batch, uint32 paramOffset);
void do_drawInstanced(Batch& batch, uint32 paramOffset);
void do_drawIndexedInstanced(Batch& batch, uint32 paramOffset);
void updateInput();
void do_setInputFormat(Batch& batch, uint32 paramOffset);
void do_setInputBuffer(Batch& batch, uint32 paramOffset);
void do_setVertexBuffer(Batch& batch, uint32 paramOffset);
void do_setIndexBuffer(Batch& batch, uint32 paramOffset);
// TODO: As long as we have gl calls explicitely issued from interface
// code, we need to be able to record and batch these calls. THe long
// term strategy is to get rid of any GL calls in favor of the HIFI GPU API

View file

@ -120,7 +120,7 @@ Resource::Size Resource::Sysmem::resize(Size size) {
Resource::Size Resource::Sysmem::setData( Size size, const Byte* bytes ) {
if (allocate(size) == size) {
if (bytes) {
if (size && bytes) {
memcpy( _data, bytes, _size );
_stamp++;
}
@ -129,7 +129,7 @@ Resource::Size Resource::Sysmem::setData( Size size, const Byte* bytes ) {
}
Resource::Size Resource::Sysmem::setSubData( Size offset, Size size, const Byte* bytes) {
if (((offset + size) <= getSize()) && bytes) {
if (size && ((offset + size) <= getSize()) && bytes) {
memcpy( _data + offset, bytes, size );
_stamp++;
return size;

View file

@ -14,6 +14,11 @@
#include <assert.h>
#include "InterfaceConfig.h"
#include "gpu/Format.h"
#include <vector>
#include <QSharedPointer>
namespace gpu {
@ -142,6 +147,8 @@ protected:
friend class Backend;
};
typedef QSharedPointer<Buffer> BufferPointer;
typedef std::vector< BufferPointer > Buffers;
};

View file

@ -0,0 +1,48 @@
//
// Stream.cpp
// interface/src/gpu
//
// Created by Sam Gateau on 10/29/2014.
// Copyright 2014 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 "Stream.h"
using namespace gpu;
void Stream::Format::evaluateCache() {
_channels.clear();
_elementTotalSize = 0;
for(AttributeMap::iterator it = _attributes.begin(); it != _attributes.end(); it++) {
Attribute& attrib = (*it).second;
Channel& channel = _channels[attrib._channel];
channel._slots.push_back(attrib._slot);
channel._stride = std::max(channel._stride, attrib.getSize() + attrib._offset);
channel._netSize += attrib.getSize();
_elementTotalSize += attrib.getSize();
}
}
bool Stream::Format::setAttribute(Slot slot, Slot channel, Element element, Offset offset, Frequency frequency) {
_attributes[slot] = Attribute((InputSlot) slot, channel, element, offset, frequency);
evaluateCache();
return true;
}
BufferStream::BufferStream() :
_buffers(),
_offsets(),
_strides()
{}
BufferStream::~BufferStream() {
}
void BufferStream::addBuffer(BufferPointer& buffer, Offset offset, Offset stride) {
_buffers.push_back(buffer);
_offsets.push_back(offset);
_strides.push_back(stride);
}

150
interface/src/gpu/Stream.h Normal file
View file

@ -0,0 +1,150 @@
//
// Stream.h
// interface/src/gpu
//
// Created by Sam Gateau on 10/29/2014.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_gpu_Stream_h
#define hifi_gpu_Stream_h
#include <assert.h>
#include "InterfaceConfig.h"
#include "gpu/Resource.h"
#include "gpu/Format.h"
#include <vector>
#include <map>
namespace gpu {
// Stream namespace class
class Stream {
public:
// Possible input slots identifiers
enum InputSlot {
POSITION = 0,
NORMAL,
COLOR,
TEXCOORD,
TANGENT,
SKIN_CLUSTER_INDEX,
SKIN_CLUSTER_WEIGHT,
NUM_INPUT_SLOTS,
};
typedef uint8 Slot;
// Frequency describer
enum Frequency {
PER_VERTEX = 0,
PER_INSTANCE,
};
// The attribute description
// Every thing that is needed to detail a stream attribute and how to interpret it
class Attribute {
public:
Attribute(Slot slot, Slot channel, Element element, Offset offset = 0, Frequency frequency = PER_VERTEX) :
_slot(slot),
_channel(channel),
_element(element),
_offset(offset),
_frequency(frequency)
{}
Attribute() :
_slot(POSITION),
_channel(0),
_element(),
_offset(0),
_frequency(PER_VERTEX)
{}
Slot _slot; // Logical slot assigned to the attribute
Slot _channel; // index of the channel where to get the data from
Element _element;
Offset _offset;
uint32 _frequency;
// Size of the
uint32 getSize() const { return _element.getSize(); }
};
// Stream Format is describing how to feed a list of attributes from a bunch of stream buffer channels
class Format {
public:
typedef std::map< Slot, Attribute > AttributeMap;
class Channel {
public:
std::vector< Slot > _slots;
std::vector< Offset > _offsets;
Offset _stride;
uint32 _netSize;
Channel() : _stride(0), _netSize(0) {}
};
typedef std::map< Slot, Channel > ChannelMap;
Format() :
_attributes(),
_elementTotalSize(0) {}
~Format() {}
uint32 getNumAttributes() const { return _attributes.size(); }
const AttributeMap& getAttributes() const { return _attributes; }
uint8 getNumChannels() const { return _channels.size(); }
const ChannelMap& getChannels() const { return _channels; }
uint32 getElementTotalSize() const { return _elementTotalSize; }
bool setAttribute(Slot slot, Slot channel, Element element, Offset offset = 0, Frequency frequency = PER_VERTEX);
protected:
AttributeMap _attributes;
ChannelMap _channels;
uint32 _elementTotalSize;
void evaluateCache();
};
typedef QSharedPointer<Format> FormatPointer;
};
typedef std::vector< Offset > Offsets;
// Buffer Stream is a container of N Buffers and their respective Offsets and Srides representing N consecutive channels.
// A Buffer Stream can be assigned to the Batch to set several stream channels in one call
class BufferStream {
public:
typedef Offsets Strides;
BufferStream();
~BufferStream();
void addBuffer(BufferPointer& buffer, Offset offset, Offset stride);
const Buffers& getBuffers() const { return _buffers; }
const Offsets& getOffsets() const { return _offsets; }
const Strides& getStrides() const { return _strides; }
uint8 getNumBuffers() const { return _buffers.size(); }
protected:
Buffers _buffers;
Offsets _offsets;
Strides _strides;
};
typedef QSharedPointer<BufferStream> BufferStreamPointer;
};
#endif

View file

@ -230,9 +230,10 @@ void DeferredLightingEffect::render() {
glTexGenfv(GL_T, GL_OBJECT_PLANE, (const GLfloat*)&tCoefficients);
// enlarge the scales slightly to account for tesselation
const float SCALE_EXPANSION = 0.1f;
const float SCALE_EXPANSION = 0.05f;
const glm::vec3& eyePoint = Application::getInstance()->getDisplayViewFrustum()->getPosition();
float nearRadius = glm::distance(eyePoint, Application::getInstance()->getDisplayViewFrustum()->getNearTopLeft());
if (!_pointLights.isEmpty()) {
_pointLight.bind();
@ -247,14 +248,14 @@ void DeferredLightingEffect::render() {
glLightfv(GL_LIGHT1, GL_DIFFUSE, (const GLfloat*)&light.diffuse);
glLightfv(GL_LIGHT1, GL_SPECULAR, (const GLfloat*)&light.specular);
glLightfv(GL_LIGHT1, GL_POSITION, (const GLfloat*)&light.position);
glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, light.constantAttenuation);
glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, light.linearAttenuation);
glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, light.quadraticAttenuation);
glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, (light.constantAttenuation > 0.f ? light.constantAttenuation : 0.f));
glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, (light.linearAttenuation > 0.f ? light.linearAttenuation : 0.f));
glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, (light.quadraticAttenuation > 0.f ? light.quadraticAttenuation : 0.f));
glPushMatrix();
float expandedRadius = light.radius * (1.0f + SCALE_EXPANSION);
if (glm::distance(eyePoint, glm::vec3(light.position)) < expandedRadius) {
if (glm::distance(eyePoint, glm::vec3(light.position)) < expandedRadius + nearRadius) {
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -1.0f);
@ -269,7 +270,7 @@ void DeferredLightingEffect::render() {
} else {
glTranslatef(light.position.x, light.position.y, light.position.z);
Application::getInstance()->getGeometryCache()->renderSphere(expandedRadius, 64, 64);
Application::getInstance()->getGeometryCache()->renderSphere(expandedRadius, 32, 32);
}
glPopMatrix();
@ -292,9 +293,9 @@ void DeferredLightingEffect::render() {
glLightfv(GL_LIGHT1, GL_DIFFUSE, (const GLfloat*)&light.diffuse);
glLightfv(GL_LIGHT1, GL_SPECULAR, (const GLfloat*)&light.specular);
glLightfv(GL_LIGHT1, GL_POSITION, (const GLfloat*)&light.position);
glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, light.constantAttenuation);
glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, light.linearAttenuation);
glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, light.quadraticAttenuation);
glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, (light.constantAttenuation > 0.f ? light.constantAttenuation : 0.f));
glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, (light.linearAttenuation > 0.f ? light.linearAttenuation : 0.f));
glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, (light.quadraticAttenuation > 0.f ? light.quadraticAttenuation : 0.f));
glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, (const GLfloat*)&light.direction);
glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, light.exponent);
glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, glm::degrees(light.cutoff));
@ -303,7 +304,7 @@ void DeferredLightingEffect::render() {
float expandedRadius = light.radius * (1.0f + SCALE_EXPANSION);
float edgeRadius = expandedRadius / glm::cos(light.cutoff);
if (glm::distance(eyePoint, glm::vec3(light.position)) < edgeRadius) {
if (glm::distance(eyePoint, glm::vec3(light.position)) < edgeRadius + nearRadius) {
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -1.0f);
@ -323,7 +324,7 @@ void DeferredLightingEffect::render() {
glRotatef(glm::degrees(glm::angle(spotRotation)), axis.x, axis.y, axis.z);
glTranslatef(0.0f, 0.0f, -light.radius * (1.0f + SCALE_EXPANSION * 0.5f));
Application::getInstance()->getGeometryCache()->renderCone(expandedRadius * glm::tan(light.cutoff),
expandedRadius, 64, 32);
expandedRadius, 32, 1);
}
glPopMatrix();

View file

@ -173,12 +173,12 @@ void GeometryCache::renderSphere(float radius, int slices, int stacks) {
for (int j = 0; j < slices; j++) {
int next = (j + 1) % slices;
*(index++) = bottom + j;
*(index++) = top + next;
*(index++) = bottom + j;
*(index++) = top + j;
*(index++) = bottom + j;
*(index++) = bottom + next;
*(index++) = bottom + j;
*(index++) = top + next;
}
}
@ -187,8 +187,8 @@ void GeometryCache::renderSphere(float radius, int slices, int stacks) {
bottom = (stacks - 2) * slices + 1;
top = bottom + slices;
for (int i = 0; i < slices; i++) {
*(index++) = bottom + i;
*(index++) = bottom + (i + 1) % slices;
*(index++) = bottom + i;
*(index++) = top;
}
@ -408,8 +408,8 @@ void GeometryCache::renderCone(float base, float height, int slices, int stacks)
GLushort* index = indexData;
for (int i = 0; i < baseTriangles; i++) {
*(index++) = 0;
*(index++) = i + 1;
*(index++) = i + 2;
*(index++) = i + 1;
}
for (int i = 1; i <= stacks; i++) {
GLushort bottom = i * slices;
@ -840,7 +840,7 @@ void NetworkGeometry::setGeometry(const FBXGeometry& geometry) {
_geometry = geometry;
foreach (const FBXMesh& mesh, _geometry.meshes) {
NetworkMesh networkMesh = { QOpenGLBuffer(QOpenGLBuffer::IndexBuffer), QOpenGLBuffer(QOpenGLBuffer::VertexBuffer) };
NetworkMesh networkMesh;
int totalIndices = 0;
foreach (const FBXMeshPart& part, mesh.parts) {
@ -870,67 +870,103 @@ void NetworkGeometry::setGeometry(const FBXGeometry& geometry) {
totalIndices += (part.quadIndices.size() + part.triangleIndices.size());
}
networkMesh.indexBuffer.create();
networkMesh.indexBuffer.bind();
networkMesh.indexBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
networkMesh.indexBuffer.allocate(totalIndices * sizeof(int));
int offset = 0;
foreach (const FBXMeshPart& part, mesh.parts) {
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, part.quadIndices.size() * sizeof(int),
part.quadIndices.constData());
offset += part.quadIndices.size() * sizeof(int);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, part.triangleIndices.size() * sizeof(int),
part.triangleIndices.constData());
offset += part.triangleIndices.size() * sizeof(int);
{
networkMesh._indexBuffer = gpu::BufferPointer(new gpu::Buffer());
networkMesh._indexBuffer->resize(totalIndices * sizeof(int));
int offset = 0;
foreach(const FBXMeshPart& part, mesh.parts) {
networkMesh._indexBuffer->setSubData(offset, part.quadIndices.size() * sizeof(int),
(gpu::Resource::Byte*) part.quadIndices.constData());
offset += part.quadIndices.size() * sizeof(int);
networkMesh._indexBuffer->setSubData(offset, part.triangleIndices.size() * sizeof(int),
(gpu::Resource::Byte*) part.triangleIndices.constData());
offset += part.triangleIndices.size() * sizeof(int);
}
}
networkMesh.indexBuffer.release();
networkMesh.vertexBuffer.create();
networkMesh.vertexBuffer.bind();
networkMesh.vertexBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
// if we don't need to do any blending, the positions/normals can be static
if (mesh.blendshapes.isEmpty()) {
int normalsOffset = mesh.vertices.size() * sizeof(glm::vec3);
int tangentsOffset = normalsOffset + mesh.normals.size() * sizeof(glm::vec3);
int colorsOffset = tangentsOffset + mesh.tangents.size() * sizeof(glm::vec3);
int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3);
int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2);
int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4);
networkMesh.vertexBuffer.allocate(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4));
networkMesh.vertexBuffer.write(0, mesh.vertices.constData(), mesh.vertices.size() * sizeof(glm::vec3));
networkMesh.vertexBuffer.write(normalsOffset, mesh.normals.constData(), mesh.normals.size() * sizeof(glm::vec3));
networkMesh.vertexBuffer.write(tangentsOffset, mesh.tangents.constData(),
mesh.tangents.size() * sizeof(glm::vec3));
networkMesh.vertexBuffer.write(colorsOffset, mesh.colors.constData(), mesh.colors.size() * sizeof(glm::vec3));
networkMesh.vertexBuffer.write(texCoordsOffset, mesh.texCoords.constData(),
mesh.texCoords.size() * sizeof(glm::vec2));
networkMesh.vertexBuffer.write(clusterIndicesOffset, mesh.clusterIndices.constData(),
mesh.clusterIndices.size() * sizeof(glm::vec4));
networkMesh.vertexBuffer.write(clusterWeightsOffset, mesh.clusterWeights.constData(),
mesh.clusterWeights.size() * sizeof(glm::vec4));
// otherwise, at least the cluster indices/weights can be static
} else {
int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3);
int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3);
int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2);
int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4);
networkMesh.vertexBuffer.allocate(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4));
networkMesh.vertexBuffer.write(0, mesh.tangents.constData(), mesh.tangents.size() * sizeof(glm::vec3));
networkMesh.vertexBuffer.write(colorsOffset, mesh.colors.constData(), mesh.colors.size() * sizeof(glm::vec3));
networkMesh.vertexBuffer.write(texCoordsOffset, mesh.texCoords.constData(),
mesh.texCoords.size() * sizeof(glm::vec2));
networkMesh.vertexBuffer.write(clusterIndicesOffset, mesh.clusterIndices.constData(),
mesh.clusterIndices.size() * sizeof(glm::vec4));
networkMesh.vertexBuffer.write(clusterWeightsOffset, mesh.clusterWeights.constData(),
mesh.clusterWeights.size() * sizeof(glm::vec4));
{
networkMesh._vertexBuffer = gpu::BufferPointer(new gpu::Buffer());
// if we don't need to do any blending, the positions/normals can be static
if (mesh.blendshapes.isEmpty()) {
int normalsOffset = mesh.vertices.size() * sizeof(glm::vec3);
int tangentsOffset = normalsOffset + mesh.normals.size() * sizeof(glm::vec3);
int colorsOffset = tangentsOffset + mesh.tangents.size() * sizeof(glm::vec3);
int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3);
int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2);
int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4);
networkMesh._vertexBuffer->resize(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4));
//networkMesh.vertexBuffer.allocate(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4));
networkMesh._vertexBuffer->setSubData(0, mesh.vertices.size() * sizeof(glm::vec3), (gpu::Resource::Byte*) mesh.vertices.constData());
networkMesh._vertexBuffer->setSubData(normalsOffset, mesh.normals.size() * sizeof(glm::vec3), (gpu::Resource::Byte*) mesh.normals.constData());
networkMesh._vertexBuffer->setSubData(tangentsOffset,
mesh.tangents.size() * sizeof(glm::vec3), (gpu::Resource::Byte*) mesh.tangents.constData());
networkMesh._vertexBuffer->setSubData(colorsOffset, mesh.colors.size() * sizeof(glm::vec3), (gpu::Resource::Byte*) mesh.colors.constData());
networkMesh._vertexBuffer->setSubData(texCoordsOffset,
mesh.texCoords.size() * sizeof(glm::vec2), (gpu::Resource::Byte*) mesh.texCoords.constData());
networkMesh._vertexBuffer->setSubData(clusterIndicesOffset,
mesh.clusterIndices.size() * sizeof(glm::vec4), (gpu::Resource::Byte*) mesh.clusterIndices.constData());
networkMesh._vertexBuffer->setSubData(clusterWeightsOffset,
mesh.clusterWeights.size() * sizeof(glm::vec4), (gpu::Resource::Byte*) mesh.clusterWeights.constData());
// otherwise, at least the cluster indices/weights can be static
networkMesh._vertexStream = gpu::BufferStreamPointer(new gpu::BufferStream());
networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, 0, sizeof(glm::vec3));
if (mesh.normals.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, normalsOffset, sizeof(glm::vec3));
if (mesh.tangents.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, tangentsOffset, sizeof(glm::vec3));
if (mesh.colors.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, colorsOffset, sizeof(glm::vec3));
if (mesh.texCoords.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, texCoordsOffset, sizeof(glm::vec2));
if (mesh.clusterIndices.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, clusterIndicesOffset, sizeof(glm::vec4));
if (mesh.clusterWeights.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, clusterWeightsOffset, sizeof(glm::vec4));
int channelNum = 0;
networkMesh._vertexFormat = gpu::Stream::FormatPointer(new gpu::Stream::Format());
networkMesh._vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::POS_XYZ), 0);
if (mesh.normals.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
if (mesh.tangents.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
if (mesh.colors.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB));
if (mesh.texCoords.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::TEXCOORD, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
if (mesh.clusterIndices.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
if (mesh.clusterWeights.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
}
else {
int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3);
int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3);
int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2);
int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4);
networkMesh._vertexBuffer->resize(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4));
networkMesh._vertexBuffer->setSubData(0, mesh.tangents.size() * sizeof(glm::vec3), (gpu::Resource::Byte*) mesh.tangents.constData());
networkMesh._vertexBuffer->setSubData(colorsOffset, mesh.colors.size() * sizeof(glm::vec3), (gpu::Resource::Byte*) mesh.colors.constData());
networkMesh._vertexBuffer->setSubData(texCoordsOffset,
mesh.texCoords.size() * sizeof(glm::vec2), (gpu::Resource::Byte*) mesh.texCoords.constData());
networkMesh._vertexBuffer->setSubData(clusterIndicesOffset,
mesh.clusterIndices.size() * sizeof(glm::vec4), (gpu::Resource::Byte*) mesh.clusterIndices.constData());
networkMesh._vertexBuffer->setSubData(clusterWeightsOffset,
mesh.clusterWeights.size() * sizeof(glm::vec4), (gpu::Resource::Byte*) mesh.clusterWeights.constData());
networkMesh._vertexStream = gpu::BufferStreamPointer(new gpu::BufferStream());
if (mesh.tangents.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, 0, sizeof(glm::vec3));
if (mesh.colors.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, colorsOffset, sizeof(glm::vec3));
if (mesh.texCoords.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, texCoordsOffset, sizeof(glm::vec2));
if (mesh.clusterIndices.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, clusterIndicesOffset, sizeof(glm::vec4));
if (mesh.clusterWeights.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, clusterWeightsOffset, sizeof(glm::vec4));
int channelNum = 0;
networkMesh._vertexFormat = gpu::Stream::FormatPointer(new gpu::Stream::Format());
networkMesh._vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::POS_XYZ));
if (mesh.normals.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
if (mesh.tangents.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
if (mesh.colors.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB));
if (mesh.texCoords.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::TEXCOORD, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
if (mesh.clusterIndices.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
if (mesh.clusterWeights.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
}
}
networkMesh.vertexBuffer.release();
_meshes.append(networkMesh);
}

View file

@ -24,6 +24,8 @@
#include <AnimationCache.h>
#include "gpu/Stream.h"
class Model;
class NetworkGeometry;
class NetworkMesh;
@ -155,9 +157,12 @@ public:
/// The state associated with a single mesh.
class NetworkMesh {
public:
QOpenGLBuffer indexBuffer;
QOpenGLBuffer vertexBuffer;
gpu::BufferPointer _indexBuffer;
gpu::BufferPointer _vertexBuffer;
gpu::BufferStreamPointer _vertexStream;
gpu::Stream::FormatPointer _vertexFormat;
QVector<NetworkMeshPart> parts;

View file

@ -137,6 +137,10 @@ void Model::initProgram(ProgramObject& program, Model::Locations& locations, int
glBindAttribLocation(program.programId(), gpu::Stream::TANGENT, "tangent");
glLinkProgram(program.programId());
locations.tangent = program.attributeLocation("tangent");
locations.alphaThreshold = program.uniformLocation("alphaThreshold");
@ -171,7 +175,13 @@ void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locati
#endif
// HACK: Assign explicitely the attribute channel to avoid a bug on Yosemite
glBindAttribLocation(program.programId(), gpu::Stream::SKIN_CLUSTER_INDEX, "clusterIndices");
glBindAttribLocation(program.programId(), gpu::Stream::SKIN_CLUSTER_WEIGHT, "clusterWeights");
glLinkProgram(program.programId());
program.bind();
@ -395,19 +405,15 @@ bool Model::updateGeometry() {
MeshState state;
state.clusterMatrices.resize(mesh.clusters.size());
_meshStates.append(state);
QOpenGLBuffer buffer;
gpu::BufferPointer buffer(new gpu::Buffer());
if (!mesh.blendshapes.isEmpty()) {
buffer.setUsagePattern(QOpenGLBuffer::DynamicDraw);
buffer.create();
buffer.bind();
buffer.allocate((mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3));
buffer.write(0, mesh.vertices.constData(), mesh.vertices.size() * sizeof(glm::vec3));
buffer.write(mesh.vertices.size() * sizeof(glm::vec3), mesh.normals.constData(),
mesh.normals.size() * sizeof(glm::vec3));
buffer.release();
buffer->resize((mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3));
buffer->setSubData(0, mesh.vertices.size() * sizeof(glm::vec3), (gpu::Resource::Byte*) mesh.vertices.constData());
buffer->setSubData(mesh.vertices.size() * sizeof(glm::vec3),
mesh.normals.size() * sizeof(glm::vec3), (gpu::Resource::Byte*) mesh.normals.constData());
}
_blendedVertexBuffers.append(buffer);
_blendedVertexBuffers.push_back(buffer);
}
foreach (const FBXAttachment& attachment, fbxGeometry.attachments) {
Model* model = new Model(this);
@ -516,6 +522,7 @@ void Model::recalcuateMeshBoxes() {
bool Model::render(float alpha, RenderMode mode, RenderArgs* args) {
PROFILE_RANGE(__FUNCTION__);
// render the attachments
foreach (Model* attachment, _attachments) {
attachment->render(alpha, mode);
@ -549,8 +556,6 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) {
// Let's introduce a gpu::Batch to capture all the calls to the graphics api
gpu::Batch batch;
GLBATCH(glEnableClientState)(GL_VERTEX_ARRAY);
GLBATCH(glEnableClientState)(GL_NORMAL_ARRAY);
GLBATCH(glDisable)(GL_COLOR_MATERIAL);
@ -665,6 +670,10 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) {
GLBATCH(glDisableClientState)(GL_NORMAL_ARRAY);
GLBATCH(glDisableClientState)(GL_VERTEX_ARRAY);
GLBATCH(glDisableClientState)(GL_TEXTURE_COORD_ARRAY);
GLBATCH(glDisableClientState)(GL_COLOR_ARRAY);
GLBATCH(glDisableVertexAttribArray)(gpu::Stream::TANGENT);
GLBATCH(glDisableVertexAttribArray)(gpu::Stream::SKIN_CLUSTER_INDEX);
GLBATCH(glDisableVertexAttribArray)(gpu::Stream::SKIN_CLUSTER_WEIGHT);
// bind with 0 to switch back to normal operation
GLBATCH(glBindBuffer)(GL_ARRAY_BUFFER, 0);
@ -1391,7 +1400,7 @@ bool Model::maybeStartBlender() {
void Model::setBlendedVertices(int blendNumber, const QWeakPointer<NetworkGeometry>& geometry,
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals) {
if (_geometry != geometry || _blendedVertexBuffers.isEmpty() || blendNumber < _appliedBlendNumber) {
if (_geometry != geometry || _blendedVertexBuffers.empty() || blendNumber < _appliedBlendNumber) {
return;
}
_appliedBlendNumber = blendNumber;
@ -1402,12 +1411,12 @@ void Model::setBlendedVertices(int blendNumber, const QWeakPointer<NetworkGeomet
if (mesh.blendshapes.isEmpty()) {
continue;
}
QOpenGLBuffer& buffer = _blendedVertexBuffers[i];
buffer.bind();
buffer.write(0, vertices.constData() + index, mesh.vertices.size() * sizeof(glm::vec3));
buffer.write(mesh.vertices.size() * sizeof(glm::vec3), normals.constData() + index,
mesh.normals.size() * sizeof(glm::vec3));
buffer.release();
gpu::BufferPointer& buffer = _blendedVertexBuffers[i];
buffer->setSubData(0, mesh.vertices.size() * sizeof(glm::vec3), (gpu::Resource::Byte*) vertices.constData() + index*sizeof(glm::vec3));
buffer->setSubData(mesh.vertices.size() * sizeof(glm::vec3),
mesh.normals.size() * sizeof(glm::vec3), (gpu::Resource::Byte*) normals.constData() + index*sizeof(glm::vec3));
index += mesh.vertices.size();
}
}
@ -1791,11 +1800,8 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl
activeProgram->link();
}
GLBATCH(glUseProgram)(activeProgram->programId());
// activeProgram->setUniformValue(activeLocations->alphaThreshold, alphaThreshold);
GLBATCH(glUniform1f)(activeLocations->alphaThreshold, alphaThreshold);
// i is the "index" from the original networkMeshes QVector...
foreach (int i, list) {
@ -1811,9 +1817,7 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl
const NetworkMesh& networkMesh = networkMeshes.at(i);
const FBXMesh& mesh = geometry.meshes.at(i);
//const_cast<QOpenGLBuffer&>(networkMesh.indexBuffer).bind();
GLBATCH(glBindBuffer)(GL_ELEMENT_ARRAY_BUFFER, const_cast<QOpenGLBuffer&>(networkMesh.indexBuffer).bufferId());
batch.setIndexBuffer(gpu::UINT32, (networkMesh._indexBuffer), 0);
int vertexCount = mesh.vertices.size();
if (vertexCount == 0) {
// sanity check
@ -1846,9 +1850,6 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl
continue; // skip this mesh
}
}
//const_cast<QOpenGLBuffer&>(networkMesh.vertexBuffer).bind();
GLBATCH(glBindBuffer)(GL_ARRAY_BUFFER, const_cast<QOpenGLBuffer&>(networkMesh.vertexBuffer).bufferId());
GLBATCH(glPushMatrix)();
//Application::getInstance()->loadTranslatedViewMatrix(_translation);
@ -1861,59 +1862,24 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl
if (state.clusterMatrices.size() > 1) {
GLBATCH(glUniformMatrix4fv)(skinLocations->clusterMatrices, state.clusterMatrices.size(), false,
(const float*)state.clusterMatrices.constData());
int offset = (mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3) +
mesh.texCoords.size() * sizeof(glm::vec2) +
(mesh.blendshapes.isEmpty() ? vertexCount * 2 * sizeof(glm::vec3) : 0);
//skinProgram->setAttributeBuffer(skinLocations->clusterIndices, GL_FLOAT, offset, 4);
GLBATCH(glVertexAttribPointer)(skinLocations->clusterIndices, 4, GL_FLOAT, GL_TRUE, 0,
reinterpret_cast<const void*>(offset));
//skinProgram->setAttributeBuffer(skinLocations->clusterWeights, GL_FLOAT,
// offset + vertexCount * sizeof(glm::vec4), 4);
GLBATCH(glVertexAttribPointer)(skinLocations->clusterWeights, 4, GL_FLOAT, GL_TRUE, 0, (const void*) (offset + vertexCount * sizeof(glm::vec4)));
//skinProgram->enableAttributeArray(skinLocations->clusterIndices);
GLBATCH(glEnableVertexAttribArray)(skinLocations->clusterIndices);
//skinProgram->enableAttributeArray(skinLocations->clusterWeights);
GLBATCH(glEnableVertexAttribArray)(skinLocations->clusterWeights);
} else {
GLBATCH(glMultMatrixf)((const GLfloat*)&state.clusterMatrices[0]);
}
if (mesh.blendshapes.isEmpty()) {
if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) {
//activeProgram->setAttributeBuffer(activeLocations->tangent, GL_FLOAT, vertexCount * 2 * sizeof(glm::vec3), 3);
GLBATCH(glVertexAttribPointer)(activeLocations->tangent, 3, GL_FLOAT, GL_TRUE, 0, (const void*)(vertexCount * 2 * sizeof(glm::vec3)));
//activeProgram->enableAttributeArray(activeLocations->tangent);
GLBATCH(glEnableVertexAttribArray)(activeLocations->tangent);
}
GLBATCH(glColorPointer)(3, GL_FLOAT, 0, (void*)(vertexCount * 2 * sizeof(glm::vec3) +
mesh.tangents.size() * sizeof(glm::vec3)));
GLBATCH(glTexCoordPointer)(2, GL_FLOAT, 0, (void*)(vertexCount * 2 * sizeof(glm::vec3) +
(mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3)));
batch.setInputFormat(networkMesh._vertexFormat);
batch.setInputStream(0, *networkMesh._vertexStream);
} else {
if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) {
//activeProgram->setAttributeBuffer(activeLocations->tangent, GL_FLOAT, 0, 3);
GLBATCH(glVertexAttribPointer)(activeLocations->tangent, 3, GL_FLOAT, GL_TRUE, 0, 0);
//activeProgram->enableAttributeArray(activeLocations->tangent);
GLBATCH(glEnableVertexAttribArray)(activeLocations->tangent);
}
GLBATCH(glColorPointer)(3, GL_FLOAT, 0, (void*)(mesh.tangents.size() * sizeof(glm::vec3)));
GLBATCH(glTexCoordPointer)(2, GL_FLOAT, 0, (void*)((mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3)));
// _blendedVertexBuffers[i].bind();
GLBATCH(glBindBuffer)(GL_ARRAY_BUFFER, _blendedVertexBuffers[i].bufferId());
batch.setInputFormat(networkMesh._vertexFormat);
batch.setInputBuffer(0, _blendedVertexBuffers[i], 0, sizeof(glm::vec3));
batch.setInputBuffer(1, _blendedVertexBuffers[i], vertexCount * sizeof(glm::vec3), sizeof(glm::vec3));
batch.setInputStream(2, *networkMesh._vertexStream);
}
GLBATCH(glVertexPointer)(3, GL_FLOAT, 0, 0);
GLBATCH(glNormalPointer)(GL_FLOAT, 0, (void*)(vertexCount * sizeof(glm::vec3)));
if (!mesh.colors.isEmpty()) {
GLBATCH(glEnableClientState)(GL_COLOR_ARRAY);
} else {
if (mesh.colors.isEmpty()) {
GLBATCH(glColor4f)(1.0f, 1.0f, 1.0f, 1.0f);
}
if (!mesh.texCoords.isEmpty()) {
GLBATCH(glEnableClientState)(GL_TEXTURE_COORD_ARRAY);
}
qint64 offset = 0;
for (int j = 0; j < networkMesh.parts.size(); j++) {
const NetworkMeshPart& networkPart = networkMesh.parts.at(j);
@ -1980,13 +1946,12 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl
meshPartsRendered++;
if (part.quadIndices.size() > 0) {
GLBATCH(glDrawRangeElements)(GL_QUADS, 0, vertexCount - 1, part.quadIndices.size(), GL_UNSIGNED_INT, (void*)offset);
batch.drawIndexed(gpu::QUADS, part.quadIndices.size(), offset);
offset += part.quadIndices.size() * sizeof(int);
}
if (part.triangleIndices.size() > 0) {
GLBATCH(glDrawRangeElements)(GL_TRIANGLES, 0, vertexCount - 1, part.triangleIndices.size(),
GL_UNSIGNED_INT, (void*)offset);
batch.drawIndexed(gpu::TRIANGLES, part.triangleIndices.size(), offset);
offset += part.triangleIndices.size() * sizeof(int);
}
@ -1997,39 +1962,23 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl
args->_quadsRendered += part.quadIndices.size() / INDICES_PER_QUAD;
}
}
if (!mesh.colors.isEmpty()) {
GLBATCH(glDisableClientState)(GL_COLOR_ARRAY);
}
if (!mesh.texCoords.isEmpty()) {
GLBATCH(glDisableClientState)(GL_TEXTURE_COORD_ARRAY);
}
if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) {
GLBATCH(glActiveTexture)(GL_TEXTURE1);
GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0);
GLBATCH(glActiveTexture)(GL_TEXTURE0);
// activeProgram->disableAttributeArray(activeLocations->tangent);
GLBATCH(glDisableVertexAttribArray)(activeLocations->tangent);
}
if (specularTextureUnit) {
GLBATCH(glActiveTexture)(specularTextureUnit);
GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0);
GLBATCH(glActiveTexture)(GL_TEXTURE0);
}
if (state.clusterMatrices.size() > 1) {
// skinProgram->disableAttributeArray(skinLocations->clusterIndices);
GLBATCH(glDisableVertexAttribArray)(skinLocations->clusterIndices);
// skinProgram->disableAttributeArray(skinLocations->clusterWeights);
GLBATCH(glDisableVertexAttribArray)(skinLocations->clusterWeights);
}
GLBATCH(glPopMatrix)();
}
//activeProgram->release();
GLBATCH(glUseProgram)(0);
return meshPartsRendered;

View file

@ -40,6 +40,8 @@ namespace gpu {
class Batch;
}
#include "gpu/Stream.h"
/// A generic 3D model displaying geometry loaded from a URL.
class Model : public QObject, public PhysicsEntity {
Q_OBJECT
@ -279,8 +281,8 @@ private:
QVector<float> _blendshapeCoefficients;
QUrl _url;
QVector<QOpenGLBuffer> _blendedVertexBuffers;
gpu::Buffers _blendedVertexBuffers;
QVector<QVector<QSharedPointer<Texture> > > _dilatedTextures;

View file

@ -25,6 +25,7 @@
#include <glm/gtc/matrix_transform.hpp>
#include "gpu/GLBackend.h"
#include "gpu/Stream.h"
// the width/height of the cached glyph textures
@ -132,12 +133,12 @@ int TextRenderer::draw(int x, int y, const char* str) {
gpu::Buffer::Size offset = sizeof(vertexBuffer) * _numGlyphsBatched;
gpu::Buffer::Size colorOffset = sizeof(colorBuffer) * _numGlyphsBatched;
if ((offset + sizeof(vertexBuffer)) > _glyphsBuffer.getSize()) {
_glyphsBuffer.append(sizeof(vertexBuffer), (gpu::Buffer::Byte*) vertexBuffer);
_glyphsColorBuffer.append(sizeof(colorBuffer), (gpu::Buffer::Byte*) colorBuffer);
if ((offset + sizeof(vertexBuffer)) > _glyphsBuffer->getSize()) {
_glyphsBuffer->append(sizeof(vertexBuffer), (gpu::Buffer::Byte*) vertexBuffer);
_glyphsColorBuffer->append(sizeof(colorBuffer), (gpu::Buffer::Byte*) colorBuffer);
} else {
_glyphsBuffer.setSubData(offset, sizeof(vertexBuffer), (gpu::Buffer::Byte*) vertexBuffer);
_glyphsColorBuffer.setSubData(colorOffset, sizeof(colorBuffer), (gpu::Buffer::Byte*) colorBuffer);
_glyphsBuffer->setSubData(offset, sizeof(vertexBuffer), (gpu::Buffer::Byte*) vertexBuffer);
_glyphsColorBuffer->setSubData(colorOffset, sizeof(colorBuffer), (gpu::Buffer::Byte*) colorBuffer);
}
_numGlyphsBatched++;
@ -178,9 +179,22 @@ TextRenderer::TextRenderer(const Properties& properties) :
_y(IMAGE_SIZE),
_rowHeight(0),
_color(properties.color),
_glyphsBuffer(),
_numGlyphsBatched(0)
_glyphsBuffer(new gpu::Buffer()),
_glyphsColorBuffer(new gpu::Buffer()),
_numGlyphsBatched(0),
_glyphsStreamFormat(new gpu::Stream::Format()),
_glyphsStream(new gpu::BufferStream())
{
_glyphsStreamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::POS_XYZ), 0);
const int NUM_POS_COORDS = 2;
const int VERTEX_TEXCOORD_OFFSET = NUM_POS_COORDS * sizeof(float);
_glyphsStreamFormat->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), VERTEX_TEXCOORD_OFFSET);
_glyphsStreamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA));
_glyphsStream->addBuffer(_glyphsBuffer, 0, _glyphsStreamFormat->getChannels().at(0)._stride);
_glyphsStream->addBuffer(_glyphsColorBuffer, 0, _glyphsStreamFormat->getChannels().at(1)._stride);
_font.setKerning(false);
}
@ -295,30 +309,17 @@ void TextRenderer::drawBatch() {
glLoadIdentity();
*/
gpu::Batch batch;
glEnable(GL_TEXTURE_2D);
// TODO: Apply the correct font atlas texture, for now only one texture per TextRenderer so it should be good
glBindTexture(GL_TEXTURE_2D, _currentTextureID);
GLuint vbo = gpu::GLBackend::getBufferID(_glyphsBuffer);
GLuint colorvbo = gpu::GLBackend::getBufferID(_glyphsColorBuffer);
batch.setInputFormat(_glyphsStreamFormat);
batch.setInputStream(0, *_glyphsStream);
batch.draw(gpu::QUADS, _numGlyphsBatched * 4, 0);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
const int NUM_POS_COORDS = 2;
const int NUM_TEX_COORDS = 2;
const int VERTEX_STRIDE = (NUM_POS_COORDS + NUM_TEX_COORDS) * sizeof(float);
const int VERTEX_TEXCOORD_OFFSET = NUM_POS_COORDS * sizeof(float);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexPointer(2, GL_FLOAT, VERTEX_STRIDE, 0);
glTexCoordPointer(2, GL_FLOAT, VERTEX_STRIDE, (GLvoid*) VERTEX_TEXCOORD_OFFSET );
glBindBuffer(GL_ARRAY_BUFFER, colorvbo);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, (GLvoid*) 0 );
glDrawArrays(GL_QUADS, 0, _numGlyphsBatched * 4);
gpu::GLBackend::renderBatch(batch);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);

View file

@ -20,6 +20,8 @@
#include <QVector>
#include "gpu/Resource.h"
#include "gpu/Stream.h"
#include "InterfaceConfig.h"
@ -105,8 +107,10 @@ private:
QColor _color;
// Graphics Buffer containing the current accumulated glyphs to render
gpu::Buffer _glyphsBuffer;
gpu::Buffer _glyphsColorBuffer;
gpu::BufferPointer _glyphsBuffer;
gpu::BufferPointer _glyphsColorBuffer;
gpu::Stream::FormatPointer _glyphsStreamFormat;
gpu::BufferStreamPointer _glyphsStream;
int _numGlyphsBatched;
static QHash<Properties, TextRenderer*> _instances;

View file

@ -26,6 +26,7 @@ AudioInjector::AudioInjector(QObject* parent) :
_sound(NULL),
_options(),
_shouldStop(false),
_loudness(0.0f),
_isFinished(false),
_currentSendPosition(0)
{
@ -35,6 +36,7 @@ AudioInjector::AudioInjector(Sound* sound, const AudioInjectorOptions& injectorO
_sound(sound),
_options(injectorOptions),
_shouldStop(false),
_loudness(0.0f),
_isFinished(false),
_currentSendPosition(0)
{
@ -44,6 +46,10 @@ void AudioInjector::setOptions(AudioInjectorOptions& options) {
_options = options;
}
float AudioInjector::getLoudness() {
return _loudness;
}
const uchar MAX_INJECTOR_VOLUME = 0xFF;
void AudioInjector::injectAudio() {
@ -102,6 +108,8 @@ void AudioInjector::injectAudio() {
quint8 volume = MAX_INJECTOR_VOLUME * _options.getVolume();
packetStream << volume;
packetStream << _options.ignorePenumbra();
QElapsedTimer timer;
timer.start();
int nextFrame = 0;
@ -115,6 +123,15 @@ void AudioInjector::injectAudio() {
int bytesToCopy = std::min(((_options.isStereo()) ? 2 : 1) * NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL,
soundByteArray.size() - _currentSendPosition);
// Measure the loudness of this frame
_loudness = 0.0f;
for (int i = 0; i < bytesToCopy; i += sizeof(int16_t)) {
_loudness += abs(*reinterpret_cast<int16_t*>(soundByteArray.data() + _currentSendPosition + i)) /
(MAX_SAMPLE_VALUE / 2.0f);
}
_loudness /= (float)(bytesToCopy / sizeof(int16_t));
memcpy(injectAudioPacket.data() + positionOptionOffset,
&_options.getPosition(),
sizeof(_options.getPosition()));

View file

@ -34,14 +34,18 @@ public slots:
void stop() { _shouldStop = true; }
void setOptions(AudioInjectorOptions& options);
void setCurrentSendPosition(int currentSendPosition) { _currentSendPosition = currentSendPosition; }
float getLoudness();
signals:
void finished();
private:
Sound* _sound;
AudioInjectorOptions _options;
bool _shouldStop;
float _loudness;
bool _isFinished;
int _currentSendPosition;
};
Q_DECLARE_METATYPE(AudioInjector*)

View file

@ -18,6 +18,7 @@ AudioInjectorOptions::AudioInjectorOptions(QObject* parent) :
_loop(false),
_orientation(glm::vec3(0.0f, 0.0f, 0.0f)),
_isStereo(false),
_ignorePenumbra(false),
_loopbackAudioInterface(NULL)
{
}
@ -28,6 +29,7 @@ AudioInjectorOptions::AudioInjectorOptions(const AudioInjectorOptions& other) {
_loop = other._loop;
_orientation = other._orientation;
_isStereo = other._isStereo;
_ignorePenumbra = other._ignorePenumbra;
_loopbackAudioInterface = other._loopbackAudioInterface;
}
@ -37,5 +39,6 @@ void AudioInjectorOptions::operator=(const AudioInjectorOptions& other) {
_loop = other._loop;
_orientation = other._orientation;
_isStereo = other._isStereo;
_ignorePenumbra = other._ignorePenumbra;
_loopbackAudioInterface = other._loopbackAudioInterface;
}

View file

@ -29,6 +29,7 @@ class AudioInjectorOptions : public QObject {
Q_PROPERTY(float volume READ getVolume WRITE setVolume)
Q_PROPERTY(bool loop READ getLoop WRITE setLoop)
Q_PROPERTY(bool isStereo READ isStereo WRITE setIsStereo)
Q_PROPERTY(bool ignorePenumbra READ ignorePenumbra WRITE setIgnorePenumbra)
public:
AudioInjectorOptions(QObject* parent = 0);
AudioInjectorOptions(const AudioInjectorOptions& other);
@ -49,6 +50,9 @@ public:
const bool isStereo() const { return _isStereo; }
void setIsStereo(const bool isStereo) { _isStereo = isStereo; }
const bool ignorePenumbra() const {return _ignorePenumbra; }
void setIgnorePenumbra(bool ignorePenumbra) { _ignorePenumbra = ignorePenumbra; }
AbstractAudioInterface* getLoopbackAudioInterface() const { return _loopbackAudioInterface; }
void setLoopbackAudioInterface(AbstractAudioInterface* loopbackAudioInterface)
{ _loopbackAudioInterface = loopbackAudioInterface; }
@ -58,6 +62,7 @@ private:
bool _loop;
glm::quat _orientation;
bool _isStereo;
bool _ignorePenumbra;
AbstractAudioInterface* _loopbackAudioInterface;
};

View file

@ -68,6 +68,14 @@ bool AudioScriptingInterface::isInjectorPlaying(AudioInjector* injector) {
return (injector != NULL);
}
float AudioScriptingInterface::getLoudness(AudioInjector* injector) {
if (injector) {
return injector->getLoudness();
} else {
return 0.0f;
}
}
void AudioScriptingInterface::injectorStopped() {
_activeInjectors.removeAll(QPointer<AudioInjector>(reinterpret_cast<AudioInjector*>(sender())));
}
}

View file

@ -26,6 +26,9 @@ public:
void stopAllInjectors();
public slots:
static float getLoudness(AudioInjector* injector);
AudioInjector* playSound(Sound* sound, const AudioInjectorOptions* injectorOptions = NULL);
void stopInjector(AudioInjector* injector);
bool isInjectorPlaying(AudioInjector* injector);
@ -36,5 +39,6 @@ private:
AudioScriptingInterface() {};
QList< QPointer<AudioInjector> > _activeInjectors;
};
#endif // hifi_AudioScriptingInterface_h

View file

@ -113,10 +113,8 @@ public:
bool lastPopSucceeded() const { return _lastPopSucceeded; };
const AudioRingBuffer::ConstIterator& getLastPopOutput() const { return _lastPopOutput; }
void setToStarved();
void setSettings(const Settings& settings);
void setMaxFramesOverDesired(int maxFramesOverDesired) { _maxFramesOverDesired = maxFramesOverDesired; }
@ -163,7 +161,7 @@ public:
float getWetLevel() const { return _wetLevel; }
void setReverb(float reverbTime, float wetLevel);
void clearReverb() { _hasReverb = false; }
public slots:
/// This function should be called every second for all the stats to function properly. If dynamic jitter buffers
/// is enabled, those stats are used to calculate _desiredJitterBufferFrames.

View file

@ -63,7 +63,9 @@ int InjectedAudioStream::parseStreamProperties(PacketType type,
quint8 attenuationByte = 0;
packetStream >> attenuationByte;
_attenuationRatio = attenuationByte / (float)MAX_INJECTOR_VOLUME;
packetStream >> _ignorePenumbra;
int numAudioBytes = packetAfterSeqNum.size() - packetStream.device()->pos();
numAudioSamples = numAudioBytes / sizeof(int16_t);

View file

@ -29,8 +29,12 @@ PositionalAudioStream::PositionalAudioStream(PositionalAudioStream::Type type, b
_orientation(0.0f, 0.0f, 0.0f, 0.0f),
_shouldLoopbackForNode(false),
_isStereo(isStereo),
_ignorePenumbra(false),
_lastPopOutputTrailingLoudness(0.0f),
_lastPopOutputLoudness(0.0f)
_lastPopOutputLoudness(0.0f),
_quietestTrailingFrameLoudness(std::numeric_limits<float>::max()),
_loudestTrailingFrameLoudness(0.0f),
_frameCounter(0)
{
}
@ -42,8 +46,9 @@ void PositionalAudioStream::resetStats() {
void PositionalAudioStream::updateLastPopOutputLoudnessAndTrailingLoudness() {
_lastPopOutputLoudness = _ringBuffer.getFrameLoudness(_lastPopOutput);
const int TRAILING_AVERAGE_FRAMES = 100;
const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES;
const int TRAILING_MUTE_THRESHOLD_FRAMES = 400;
const int TRAILING_LOUDNESS_FRAMES = 200;
const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_LOUDNESS_FRAMES;
const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO;
const float LOUDNESS_EPSILON = 0.000001f;
@ -56,6 +61,17 @@ void PositionalAudioStream::updateLastPopOutputLoudnessAndTrailingLoudness() {
_lastPopOutputTrailingLoudness = 0;
}
}
if (_frameCounter++ == TRAILING_MUTE_THRESHOLD_FRAMES) {
_frameCounter = 0;
_quietestTrailingFrameLoudness = std::numeric_limits<float>::max();
_loudestTrailingFrameLoudness = 0.0f;
}
if (_lastPopOutputLoudness < _quietestTrailingFrameLoudness) {
_quietestTrailingFrameLoudness = _lastPopOutputLoudness;
}
if (_lastPopOutputLoudness > _loudestTrailingFrameLoudness) {
_loudestTrailingFrameLoudness = _lastPopOutputLoudness;
}
}
int PositionalAudioStream::parsePositionalData(const QByteArray& positionalByteArray) {

View file

@ -36,12 +36,16 @@ public:
void updateLastPopOutputLoudnessAndTrailingLoudness();
float getLastPopOutputTrailingLoudness() const { return _lastPopOutputTrailingLoudness; }
float getLastPopOutputLoudness() const { return _lastPopOutputLoudness; }
float getQuietestTrailingFrameLoudness() const { return _quietestTrailingFrameLoudness; }
float getLoudestTrailingFrameLoudness() const { return _loudestTrailingFrameLoudness; }
bool shouldLoopbackForNode() const { return _shouldLoopbackForNode; }
bool isStereo() const { return _isStereo; }
bool ignorePenumbraFilter() { return _ignorePenumbra; }
PositionalAudioStream::Type getType() const { return _type; }
const glm::vec3& getPosition() const { return _position; }
const glm::quat& getOrientation() const { return _orientation; }
protected:
// disallow copying of PositionalAudioStream objects
@ -57,9 +61,14 @@ protected:
bool _shouldLoopbackForNode;
bool _isStereo;
// Ignore penumbra filter
bool _ignorePenumbra;
float _lastPopOutputTrailingLoudness;
float _lastPopOutputLoudness;
float _quietestTrailingFrameLoudness;
float _loudestTrailingFrameLoudness;
int _frameCounter;
};
#endif // hifi_PositionalAudioStream_h

View file

@ -59,6 +59,7 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) {
_lastUpdated = 0;
_created = 0; // TODO: when do we actually want to make this "now"
_changedOnServer = 0;
_position = glm::vec3(0,0,0);
_rotation = DEFAULT_ROTATION;
@ -87,6 +88,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) {
_lastEditedFromRemoteInRemoteTime = 0;
_lastUpdated = 0;
_created = 0;
_changedOnServer = 0;
initFromEntityItemID(entityItemID);
}
@ -97,6 +99,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert
_lastEditedFromRemoteInRemoteTime = 0;
_lastUpdated = 0;
_created = properties.getCreated();
_changedOnServer = 0;
initFromEntityItemID(entityItemID);
setProperties(properties, true); // force copy
}

View file

@ -70,10 +70,14 @@ public:
/// Last edited time of this entity universal usecs
quint64 getLastEdited() const { return _lastEdited; }
void setLastEdited(quint64 lastEdited) { _lastEdited = _lastUpdated = lastEdited; }
void setLastEdited(quint64 lastEdited)
{ _lastEdited = _lastUpdated = lastEdited; _changedOnServer = glm::max(lastEdited, _changedOnServer); }
float getEditedAgo() const /// Elapsed seconds since this entity was last edited
{ return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; }
void markAsChangedOnServer() { _changedOnServer = usecTimestampNow(); }
quint64 getLastChangedOnServer() const { return _changedOnServer; }
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;
@ -268,6 +272,7 @@ protected:
quint64 _lastEditedFromRemote; // this is the last time we received and edit from the server
quint64 _lastEditedFromRemoteInRemoteTime; // time in server time space the last time we received and edit from the server
quint64 _created;
quint64 _changedOnServer;
glm::vec3 _position;
glm::vec3 _dimensions;

View file

@ -497,6 +497,7 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char
// if the entityItem exists, then update it
if (existingEntity) {
updateEntity(entityItemID, properties);
existingEntity->markAsChangedOnServer();
} else {
qDebug() << "User attempted to edit an unknown entity. ID:" << entityItemID;
}
@ -505,6 +506,7 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char
entityItemID = assignEntityID(entityItemID);
EntityItem* newEntity = addEntity(entityItemID, properties);
if (newEntity) {
newEntity->markAsChangedOnServer();
notifyNewlyCreatedEntity(*newEntity, senderNode);
}
}
@ -1069,6 +1071,24 @@ void EntityTree::dumpTree() {
recurseTreeWithOperator(&theOperator);
}
class PruneOperator : public RecurseOctreeOperator {
public:
virtual bool preRecursion(OctreeElement* element) { return true; }
virtual bool postRecursion(OctreeElement* element);
};
bool PruneOperator::postRecursion(OctreeElement* element) {
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
entityTreeElement->pruneChildren();
return true;
}
void EntityTree::pruneTree() {
// First, look for the existing entity in the tree..
PruneOperator theOperator;
recurseTreeWithOperator(&theOperator);
}
void EntityTree::sendEntities(EntityEditPacketSender* packetSender, EntityTree* localTree, float x, float y, float z) {
SendEntitiesOperationArgs args;
args.packetSender = packetSender;

View file

@ -131,6 +131,7 @@ public:
void resetContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element);
void debugDumpMap();
virtual void dumpTree();
virtual void pruneTree();
void sendEntities(EntityEditPacketSender* packetSender, EntityTree* localTree, float x, float y, float z);

View file

@ -238,7 +238,7 @@ void EntityTreeElement::elementEncodeComplete(EncodeBitstreamParams& params, Oct
OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData* packetData,
EncodeBitstreamParams& params) const {
OctreeElement::AppendState appendElementState = OctreeElement::COMPLETED; // assume the best...
// first, check the params.extraEncodeData to see if there's any partial re-encode data for this element
@ -289,7 +289,8 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
for (uint16_t i = 0; i < _entityItems->size(); i++) {
EntityItem* entity = (*_entityItems)[i];
bool includeThisEntity = true;
if (!params.forceSendScene && entity->getLastEdited() < params.lastViewFrustumSent) {
if (!params.forceSendScene && entity->getLastChangedOnServer() < params.lastViewFrustumSent) {
includeThisEntity = false;
}
@ -324,7 +325,6 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
if (successAppendEntityCount) {
foreach (uint16_t i, indexesOfEntitiesToInclude) {
EntityItem* entity = (*_entityItems)[i];
LevelDetails entityLevel = packetData->startLevel();
OctreeElement::AppendState appendEntityState = entity->appendEntityData(packetData,
params, entityTreeElementExtraEncodeData);
@ -812,11 +812,20 @@ bool EntityTreeElement::pruneChildren() {
void EntityTreeElement::debugDump() {
qDebug() << "EntityTreeElement...";
qDebug() << "entity count:" << _entityItems->size();
qDebug() << "cube:" << getAACube();
for (uint16_t i = 0; i < _entityItems->size(); i++) {
EntityItem* entity = (*_entityItems)[i];
entity->debugDump();
AACube temp = getAACube();
temp.scale((float)TREE_SCALE);
qDebug() << " cube:" << temp;
qDebug() << " has child elements:" << getChildCount();
if (_entityItems->size()) {
qDebug() << " has entities:" << _entityItems->size();
qDebug() << "--------------------------------------------------";
for (uint16_t i = 0; i < _entityItems->size(); i++) {
EntityItem* entity = (*_entityItems)[i];
entity->debugDump();
}
qDebug() << "--------------------------------------------------";
} else {
qDebug() << " NO entities!";
}
}

View file

@ -54,6 +54,8 @@ PacketVersion versionForPacketType(PacketType type) {
return 4;
case PacketTypeMixedAudio:
return 1;
case PacketTypeInjectAudio:
return 1;
case PacketTypeAvatarData:
return 3;
case PacketTypeAvatarIdentity:

View file

@ -352,6 +352,7 @@ public:
void setIsClient(bool isClient) { _isServer = !isClient; }
virtual void dumpTree() { };
virtual void pruneTree() { };
signals:
void importSize(float x, float y, float z);

View file

@ -246,9 +246,7 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, unsigned ch
// But we can't really do that with a packed message, since each edit message could be destined
// for a different server... So we need to actually manage multiple queued packets... one
// for each server
_packetsQueueLock.lock();
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
// only send to the NodeTypes that are getMyNodeType()
if (node->getActiveSocket() && node->getType() == getMyNodeType()) {
@ -277,12 +275,12 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, unsigned ch
if ((type != packetBuffer._currentType && packetBuffer._currentSize > 0) ||
(packetBuffer._currentSize + length >= (size_t)_maxPacketSize)) {
releaseQueuedPacket(packetBuffer);
initializePacket(packetBuffer, type);
initializePacket(packetBuffer, type, node->getClockSkewUsec());
}
// If the buffer is empty and not correctly initialized for our type...
if (type != packetBuffer._currentType && packetBuffer._currentSize == 0) {
initializePacket(packetBuffer, type);
initializePacket(packetBuffer, type, node->getClockSkewUsec());
}
// This is really the first time we know which server/node this particular edit message
@ -330,14 +328,14 @@ void OctreeEditPacketSender::releaseQueuedPacket(EditPacketBuffer& packetBuffer)
_releaseQueuedPacketMutex.unlock();
}
void OctreeEditPacketSender::initializePacket(EditPacketBuffer& packetBuffer, PacketType type) {
void OctreeEditPacketSender::initializePacket(EditPacketBuffer& packetBuffer, PacketType type, int nodeClockSkew) {
packetBuffer._currentSize = populatePacketHeader(reinterpret_cast<char*>(&packetBuffer._currentBuffer[0]), type);
// skip over sequence number for now; will be packed when packet is ready to be sent out
packetBuffer._currentSize += sizeof(quint16);
// pack in timestamp
quint64 now = usecTimestampNow();
quint64 now = usecTimestampNow() + nodeClockSkew;
quint64* timeAt = (quint64*)&packetBuffer._currentBuffer[packetBuffer._currentSize];
*timeAt = now;
packetBuffer._currentSize += sizeof(quint64); // nudge past timestamp

View file

@ -101,7 +101,7 @@ protected:
void queuePacketToNode(const QUuid& nodeID, unsigned char* buffer, size_t length, qint64 satoshiCost = 0);
void queuePendingPacketToNodes(PacketType type, unsigned char* buffer, size_t length, qint64 satoshiCost = 0);
void queuePacketToNodes(unsigned char* buffer, size_t length, qint64 satoshiCost = 0);
void initializePacket(EditPacketBuffer& packetBuffer, PacketType type);
void initializePacket(EditPacketBuffer& packetBuffer, PacketType type, int nodeClockSkew);
void releaseQueuedPacket(EditPacketBuffer& packetBuffer); // releases specific queued packet
void processPreServerExistsPackets();

View file

@ -36,6 +36,7 @@ bool OctreePersistThread::process() {
{
PerformanceWarning warn(true, "Loading Octree File", true);
persistantFileRead = _tree->readFromSVOFile(_filename.toLocal8Bit().constData());
_tree->pruneTree();
}
_tree->unlock();
@ -80,10 +81,14 @@ bool OctreePersistThread::process() {
// check the dirty bit and persist here...
_lastCheck = usecTimestampNow();
if (_tree->isDirty()) {
qDebug() << "saving Octrees to file " << _filename << "...";
qDebug() << "pruning Octree before saving...";
_tree->pruneTree();
qDebug() << "DONE pruning Octree before saving...";
qDebug() << "saving Octree to file " << _filename << "...";
_tree->writeToSVOFile(_filename.toLocal8Bit().constData());
_tree->clearDirtyBit(); // tree is clean after saving
qDebug("DONE saving Octrees to file...");
qDebug("DONE saving Octree to file...");
}
}
}