mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 09:24:00 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into fix-camera-update
This commit is contained in:
commit
0c5c4679fb
56 changed files with 972 additions and 304 deletions
|
@ -129,6 +129,12 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) {
|
|||
AvatarAudioStream* listenerAudioStream = static_cast<AudioMixerClientData*>(listener->getLinkedData())->getAvatarAudioStream();
|
||||
AudioMixerClientData* listenerData = static_cast<AudioMixerClientData*>(listener->getLinkedData());
|
||||
|
||||
// if we received an invalid position from this listener, then refuse to make them a mix
|
||||
// because we don't know how to do it properly
|
||||
if (!listenerAudioStream->hasValidPosition()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// zero out the mix for this listener
|
||||
memset(_mixSamples, 0, sizeof(_mixSamples));
|
||||
|
||||
|
@ -244,12 +250,18 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) {
|
|||
|
||||
void AudioMixerSlave::throttleStream(AudioMixerClientData& listenerNodeData, const QUuid& sourceNodeID,
|
||||
const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd) {
|
||||
addStream(listenerNodeData, sourceNodeID, listeningNodeStream, streamToAdd, true);
|
||||
// only throttle this stream to the mix if it has a valid position, we won't know how to mix it otherwise
|
||||
if (streamToAdd.hasValidPosition()) {
|
||||
addStream(listenerNodeData, sourceNodeID, listeningNodeStream, streamToAdd, true);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioMixerSlave::mixStream(AudioMixerClientData& listenerNodeData, const QUuid& sourceNodeID,
|
||||
const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd) {
|
||||
addStream(listenerNodeData, sourceNodeID, listeningNodeStream, streamToAdd, false);
|
||||
// only add the stream to the mix if it has a valid position, we won't know how to mix it otherwise
|
||||
if (streamToAdd.hasValidPosition()) {
|
||||
addStream(listenerNodeData, sourceNodeID, listeningNodeStream, streamToAdd, false);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioMixerSlave::addStream(AudioMixerClientData& listenerNodeData, const QUuid& sourceNodeID,
|
||||
|
|
|
@ -161,7 +161,7 @@ NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QStrin
|
|||
} else if (_server->_settingsManager.hasPermissionsForMachineFingerprint(machineFingerprint)) {
|
||||
userPerms = _server->_settingsManager.getPermissionsForMachineFingerprint(machineFingerprint);
|
||||
#ifdef WANT_DEBUG
|
||||
qDebug(() << "| user-permissions: specific Machine Fingerprint matches, so: " << userPerms;
|
||||
qDebug() << "| user-permissions: specific Machine Fingerprint matches, so: " << userPerms;
|
||||
#endif
|
||||
} else if (_server->_settingsManager.hasPermissionsForIP(senderAddress)) {
|
||||
// this user comes from an IP we have in our permissions table, apply those permissions
|
||||
|
@ -187,7 +187,7 @@ NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QStrin
|
|||
} else if (_server->_settingsManager.hasPermissionsForMachineFingerprint(machineFingerprint)) {
|
||||
userPerms = _server->_settingsManager.getPermissionsForMachineFingerprint(machineFingerprint);
|
||||
#ifdef WANT_DEBUG
|
||||
qDebug(() << "| user-permissions: specific Machine Fingerprint matches, so: " << userPerms;
|
||||
qDebug() << "| user-permissions: specific Machine Fingerprint matches, so: " << userPerms;
|
||||
#endif
|
||||
} else if (_server->_settingsManager.hasPermissionsForIP(senderAddress)) {
|
||||
// this user comes from an IP we have in our permissions table, apply those permissions
|
||||
|
@ -393,9 +393,12 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
|
|||
|
||||
QString verifiedUsername; // if this remains empty, consider this an anonymous connection attempt
|
||||
if (!username.isEmpty()) {
|
||||
if (usernameSignature.isEmpty()) {
|
||||
const QUuid& connectionToken = _connectionTokenHash.value(username.toLower());
|
||||
|
||||
if (usernameSignature.isEmpty() || connectionToken.isNull()) {
|
||||
// user is attempting to prove their identity to us, but we don't have enough information
|
||||
sendConnectionTokenPacket(username, nodeConnection.senderSockAddr);
|
||||
|
||||
// ask for their public key right now to make sure we have it
|
||||
requestUserPublicKey(username, true);
|
||||
getGroupMemberships(username); // optimistically get started on group memberships
|
||||
|
|
BIN
interface/resources/qml/hifi/commerce/common/images/loader.gif
Normal file
BIN
interface/resources/qml/hifi/commerce/common/images/loader.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
|
@ -58,6 +58,9 @@ Item {
|
|||
|
||||
if (result.status === 'success') {
|
||||
root.nextActiveView = 'paymentSuccess';
|
||||
if (sendPubliclyCheckbox.checked && sendMoneyStep.referrer === "nearby") {
|
||||
sendSignalToWallet({method: 'sendMoney_sendPublicly', recipient: sendMoneyStep.selectedRecipientNodeID, amount: parseInt(amountTextField.text)});
|
||||
}
|
||||
} else {
|
||||
root.nextActiveView = 'paymentFailure';
|
||||
}
|
||||
|
@ -104,6 +107,12 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
HifiCommerceCommon.CommerceLightbox {
|
||||
id: lightboxPopup;
|
||||
visible: false;
|
||||
anchors.fill: parent;
|
||||
}
|
||||
|
||||
// Send Money Home BEGIN
|
||||
Item {
|
||||
id: sendMoneyHome;
|
||||
|
@ -921,7 +930,7 @@ Item {
|
|||
id: optionalMessage;
|
||||
property int maximumLength: 72;
|
||||
property string previousText: text;
|
||||
placeholderText: "<i>Optional Message (" + maximumLength + " character limit)</i>";
|
||||
placeholderText: "<i>Optional Public Message (" + maximumLength + " character limit)</i>";
|
||||
font.family: firaSansSemiBold.name;
|
||||
font.pixelSize: 20;
|
||||
// Anchors
|
||||
|
@ -971,16 +980,54 @@ Item {
|
|||
|
||||
HifiControlsUit.CheckBox {
|
||||
id: sendPubliclyCheckbox;
|
||||
visible: false; // FIXME ONCE PARTICLE EFFECTS ARE IN
|
||||
text: "Send Publicly"
|
||||
visible: sendMoneyStep.referrer === "nearby";
|
||||
checked: Settings.getValue("sendMoneyNearbyPublicly", true);
|
||||
text: "Show Effect"
|
||||
// Anchors
|
||||
anchors.top: messageContainer.bottom;
|
||||
anchors.topMargin: 16;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 20;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 16;
|
||||
boxSize: 24;
|
||||
width: 110;
|
||||
boxSize: 28;
|
||||
onCheckedChanged: {
|
||||
Settings.setValue("sendMoneyNearbyPublicly", checked);
|
||||
}
|
||||
}
|
||||
RalewaySemiBold {
|
||||
id: sendPubliclyCheckboxHelp;
|
||||
visible: sendPubliclyCheckbox.visible;
|
||||
text: "[?]";
|
||||
// Anchors
|
||||
anchors.left: sendPubliclyCheckbox.right;
|
||||
anchors.leftMargin: 8;
|
||||
anchors.verticalCenter: sendPubliclyCheckbox.verticalCenter;
|
||||
height: 30;
|
||||
width: paintedWidth;
|
||||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
color: hifi.colors.blueAccent;
|
||||
MouseArea {
|
||||
enabled: sendPubliclyCheckboxHelp.visible;
|
||||
anchors.fill: parent;
|
||||
hoverEnabled: true;
|
||||
onEntered: {
|
||||
parent.color = hifi.colors.blueHighlight;
|
||||
}
|
||||
onExited: {
|
||||
parent.color = hifi.colors.blueAccent;
|
||||
}
|
||||
onClicked: {
|
||||
lightboxPopup.titleText = "Send Money Effect";
|
||||
lightboxPopup.bodyImageSource = "../wallet/sendMoney/images/send-money-effect-sm.jpg"; // Path relative to CommerceLightbox.qml
|
||||
lightboxPopup.bodyText = "Enabling this option will create a particle effect between you and " +
|
||||
"your recipient that is visible to everyone nearby.";
|
||||
lightboxPopup.button1text = "CLOSE";
|
||||
lightboxPopup.button1method = "root.visible = false;"
|
||||
lightboxPopup.visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
|
@ -1538,6 +1585,8 @@ Item {
|
|||
sendMoneyStep.selectedRecipientProfilePic = "";
|
||||
amountTextField.text = "";
|
||||
optionalMessage.text = "";
|
||||
sendPubliclyCheckbox.checked = Settings.getValue("sendMoneyNearbyPublicly", true);
|
||||
sendMoneyStep.referrer = "";
|
||||
}
|
||||
|
||||
//
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
|
@ -1046,7 +1046,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch);
|
||||
|
||||
// you might think we could just do this in NodeList but we only want this connection for Interface
|
||||
connect(nodeList.data(), &NodeList::limitOfSilentDomainCheckInsReached, nodeList.data(), &NodeList::reset);
|
||||
connect(&nodeList->getDomainHandler(), SIGNAL(limitOfSilentDomainCheckInsReached()),
|
||||
nodeList.data(), SLOT(reset()));
|
||||
|
||||
auto dialogsManager = DependencyManager::get<DialogsManager>();
|
||||
connect(accountManager.data(), &AccountManager::authRequired, dialogsManager.data(), &DialogsManager::showLoginDialog);
|
||||
|
@ -2296,16 +2297,16 @@ void Application::initializeGL() {
|
|||
#endif
|
||||
_renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, !DISABLE_DEFERRED, render::ItemKey::TAG_BITS_0, render::ItemKey::TAG_BITS_0);
|
||||
|
||||
#ifdef Q_OS_OSX
|
||||
DeadlockWatchdogThread::resume();
|
||||
#endif
|
||||
|
||||
_renderEngine->load();
|
||||
_renderEngine->registerScene(_main3DScene);
|
||||
|
||||
// Now that OpenGL is initialized, we are sure we have a valid context and can create the various pipeline shaders with success.
|
||||
DependencyManager::get<GeometryCache>()->initializeShapePipelines();
|
||||
|
||||
#ifdef Q_OS_OSX
|
||||
DeadlockWatchdogThread::resume();
|
||||
#endif
|
||||
|
||||
_offscreenContext = new OffscreenGLCanvas();
|
||||
_offscreenContext->setObjectName("MainThreadContext");
|
||||
_offscreenContext->create(_glWidget->qglContext());
|
||||
|
|
|
@ -396,11 +396,11 @@ QString WindowScriptingInterface::protocolSignature() {
|
|||
}
|
||||
|
||||
int WindowScriptingInterface::getInnerWidth() {
|
||||
return qApp->getDeviceSize().x;
|
||||
return qApp->getWindow()->geometry().width();
|
||||
}
|
||||
|
||||
int WindowScriptingInterface::getInnerHeight() {
|
||||
return qApp->getDeviceSize().y;
|
||||
return qApp->getWindow()->geometry().height() - qApp->getPrimaryMenu()->geometry().height();
|
||||
}
|
||||
|
||||
glm::vec2 WindowScriptingInterface::getDeviceSize() const {
|
||||
|
|
|
@ -1754,7 +1754,6 @@ void Rig::copyJointsFromJointData(const QVector<JointData>& jointDataVec) {
|
|||
const AnimPoseVec& relativeDefaultPoses = _animSkeleton->getRelativeDefaultPoses();
|
||||
for (int i = 0; i < numJoints; i++) {
|
||||
const JointData& data = jointDataVec.at(i);
|
||||
_internalPoseSet._relativePoses[i].scale() = Vectors::ONE;
|
||||
_internalPoseSet._relativePoses[i].rot() = rotations[i];
|
||||
if (data.translationIsDefaultPose) {
|
||||
_internalPoseSet._relativePoses[i].trans() = relativeDefaultPoses[i].trans();
|
||||
|
|
|
@ -49,6 +49,9 @@ void AbstractAudioInterface::emitAudioPacket(const void* audioData, size_t bytes
|
|||
audioPacket->writePrimitive(channelFlag);
|
||||
}
|
||||
|
||||
// at this point we'd better be sending the mixer a valid position, or it won't consider us for mixing
|
||||
assert(!isNaN(transform.getTranslation()));
|
||||
|
||||
// pack the three float positions
|
||||
audioPacket->writePrimitive(transform.getTranslation());
|
||||
// pack the orientation
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <glm/detail/func_common.hpp>
|
||||
#include <QtCore/QDataStream>
|
||||
|
||||
#include <LogHandler.h>
|
||||
#include <Node.h>
|
||||
#include <udt/PacketHeaders.h>
|
||||
#include <UUID.h>
|
||||
|
@ -76,6 +77,19 @@ int PositionalAudioStream::parsePositionalData(const QByteArray& positionalByteA
|
|||
QDataStream packetStream(positionalByteArray);
|
||||
|
||||
packetStream.readRawData(reinterpret_cast<char*>(&_position), sizeof(_position));
|
||||
|
||||
// if the client sends us a bad position, flag it so that we don't consider this stream for mixing
|
||||
if (glm::isnan(_position.x) || glm::isnan(_position.y) || glm::isnan(_position.z)) {
|
||||
static const QString INVALID_POSITION_REGEX = "PositionalAudioStream unpacked invalid position for node";
|
||||
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(INVALID_POSITION_REGEX);
|
||||
|
||||
qDebug() << "PositionalAudioStream unpacked invalid position for node" << uuidStringWithoutCurlyBraces(getNodeID());
|
||||
|
||||
_hasValidPosition = false;
|
||||
} else {
|
||||
_hasValidPosition = true;
|
||||
}
|
||||
|
||||
packetStream.readRawData(reinterpret_cast<char*>(&_orientation), sizeof(_orientation));
|
||||
packetStream.readRawData(reinterpret_cast<char*>(&_avatarBoundingBoxCorner), sizeof(_avatarBoundingBoxCorner));
|
||||
packetStream.readRawData(reinterpret_cast<char*>(&_avatarBoundingBoxScale), sizeof(_avatarBoundingBoxScale));
|
||||
|
|
|
@ -43,12 +43,15 @@ public:
|
|||
|
||||
bool shouldLoopbackForNode() const { return _shouldLoopbackForNode; }
|
||||
bool isStereo() const { return _isStereo; }
|
||||
|
||||
PositionalAudioStream::Type getType() const { return _type; }
|
||||
|
||||
const glm::vec3& getPosition() const { return _position; }
|
||||
const glm::quat& getOrientation() const { return _orientation; }
|
||||
const glm::vec3& getAvatarBoundingBoxCorner() const { return _avatarBoundingBoxCorner; }
|
||||
const glm::vec3& getAvatarBoundingBoxScale() const { return _avatarBoundingBoxScale; }
|
||||
|
||||
bool hasValidPosition() const { return _hasValidPosition; }
|
||||
|
||||
protected:
|
||||
// disallow copying of PositionalAudioStream objects
|
||||
|
@ -75,6 +78,8 @@ protected:
|
|||
float _quietestTrailingFrameLoudness;
|
||||
float _quietestFrameLoudness;
|
||||
int _frameCounter;
|
||||
|
||||
bool _hasValidPosition { false };
|
||||
};
|
||||
|
||||
#endif // hifi_PositionalAudioStream_h
|
||||
|
|
|
@ -398,7 +398,7 @@ void HmdDisplayPlugin::HUDRenderer::updatePipeline() {
|
|||
auto vs = gpu::Shader::createVertex(std::string(hmd_ui_vert));
|
||||
auto ps = gpu::Shader::createPixel(std::string(hmd_ui_frag));
|
||||
auto program = gpu::Shader::createProgram(vs, ps);
|
||||
gpu::gl::GLBackend::makeProgram(*program, gpu::Shader::BindingSet());
|
||||
gpu::Shader::makeProgram(*program, gpu::Shader::BindingSet());
|
||||
uniformsLocation = program->getUniformBuffers().findLocation("hudBuffer");
|
||||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
|
|
|
@ -99,7 +99,7 @@ const float MARCHING_CUBE_COLLISION_HULL_OFFSET = 0.5;
|
|||
|
||||
In RenderablePolyVoxEntityItem::render, these flags are checked and changes are propagated along the chain.
|
||||
decompressVolumeData() is called to decompress _voxelData into _volData. recomputeMesh() is called to invoke the
|
||||
polyVox surface extractor to create _mesh (as well as set Simulation _dirtyFlags). Because Simulation::DIRTY_SHAPE
|
||||
polyVox surface extractor to create _mesh (as well as set Simulation _flags). Because Simulation::DIRTY_SHAPE
|
||||
is set, isReadyToComputeShape() gets called and _shape is created either from _volData or _shape, depending on
|
||||
the surface style.
|
||||
|
||||
|
@ -1138,7 +1138,7 @@ void RenderablePolyVoxEntityItem::setMesh(graphics::MeshPointer mesh) {
|
|||
bool neighborsNeedUpdate;
|
||||
withWriteLock([&] {
|
||||
if (!_collisionless) {
|
||||
_dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
|
||||
_flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
|
||||
}
|
||||
_mesh = mesh;
|
||||
_meshDirty = true;
|
||||
|
|
|
@ -933,7 +933,7 @@ void EntityItem::setDensity(float density) {
|
|||
withWriteLock([&] {
|
||||
if (_density != clampedDensity) {
|
||||
_density = clampedDensity;
|
||||
_dirtyFlags |= Simulation::DIRTY_MASS;
|
||||
_flags |= Simulation::DIRTY_MASS;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -958,7 +958,7 @@ void EntityItem::setMass(float mass) {
|
|||
withWriteLock([&] {
|
||||
if (_density != newDensity) {
|
||||
_density = newDensity;
|
||||
_dirtyFlags |= Simulation::DIRTY_MASS;
|
||||
_flags |= Simulation::DIRTY_MASS;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1623,41 +1623,42 @@ void EntityItem::setParentID(const QUuid& value) {
|
|||
if (!value.isNull() && tree) {
|
||||
EntityItemPointer entity = tree->findEntityByEntityItemID(value);
|
||||
if (entity) {
|
||||
newParentNoBootstrapping = entity->getDirtyFlags() & Simulation::NO_BOOTSTRAPPING;
|
||||
newParentNoBootstrapping = entity->getSpecialFlags() & Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING;
|
||||
}
|
||||
}
|
||||
|
||||
if (!oldParentID.isNull() && tree) {
|
||||
EntityItemPointer entity = tree->findEntityByEntityItemID(oldParentID);
|
||||
if (entity) {
|
||||
oldParentNoBootstrapping = entity->getDirtyFlags() & Simulation::NO_BOOTSTRAPPING;
|
||||
oldParentNoBootstrapping = entity->getDirtyFlags() & Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING;
|
||||
}
|
||||
}
|
||||
|
||||
if (!value.isNull() && (value == Physics::getSessionUUID() || value == AVATAR_SELF_ID)) {
|
||||
newParentNoBootstrapping |= Simulation::NO_BOOTSTRAPPING;
|
||||
newParentNoBootstrapping |= Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING;
|
||||
}
|
||||
|
||||
if (!oldParentID.isNull() && (oldParentID == Physics::getSessionUUID() || oldParentID == AVATAR_SELF_ID)) {
|
||||
oldParentNoBootstrapping |= Simulation::NO_BOOTSTRAPPING;
|
||||
oldParentNoBootstrapping |= Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING;
|
||||
}
|
||||
|
||||
if ((bool)(oldParentNoBootstrapping ^ newParentNoBootstrapping)) {
|
||||
if ((bool)(newParentNoBootstrapping & Simulation::NO_BOOTSTRAPPING)) {
|
||||
markDirtyFlags(Simulation::NO_BOOTSTRAPPING);
|
||||
forEachDescendant([&](SpatiallyNestablePointer object) {
|
||||
if (object->getNestableType() == NestableType::Entity) {
|
||||
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
|
||||
entity->markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP | Simulation::NO_BOOTSTRAPPING);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
clearDirtyFlags(Simulation::NO_BOOTSTRAPPING);
|
||||
if ((bool)(newParentNoBootstrapping & Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING)) {
|
||||
markSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING);
|
||||
forEachDescendant([&](SpatiallyNestablePointer object) {
|
||||
if (object->getNestableType() == NestableType::Entity) {
|
||||
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
|
||||
entity->markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP);
|
||||
entity->clearDirtyFlags(Simulation::NO_BOOTSTRAPPING);
|
||||
entity->markSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
clearSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING);
|
||||
forEachDescendant([&](SpatiallyNestablePointer object) {
|
||||
if (object->getNestableType() == NestableType::Entity) {
|
||||
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
|
||||
entity->markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP);
|
||||
entity->clearSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1694,7 +1695,7 @@ void EntityItem::setUnscaledDimensions(const glm::vec3& value) {
|
|||
locationChanged();
|
||||
dimensionsChanged();
|
||||
withWriteLock([&] {
|
||||
_dirtyFlags |= (Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
|
||||
_flags |= (Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
|
||||
_queryAACubeSet = false;
|
||||
});
|
||||
}
|
||||
|
@ -1703,7 +1704,7 @@ void EntityItem::setUnscaledDimensions(const glm::vec3& value) {
|
|||
void EntityItem::setRotation(glm::quat rotation) {
|
||||
if (getLocalOrientation() != rotation) {
|
||||
setLocalOrientation(rotation);
|
||||
_dirtyFlags |= Simulation::DIRTY_ROTATION;
|
||||
_flags |= Simulation::DIRTY_ROTATION;
|
||||
forEachDescendant([&](SpatiallyNestablePointer object) {
|
||||
if (object->getNestableType() == NestableType::Entity) {
|
||||
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
|
||||
|
@ -1733,7 +1734,7 @@ void EntityItem::setVelocity(const glm::vec3& value) {
|
|||
velocity = value;
|
||||
}
|
||||
setLocalVelocity(velocity);
|
||||
_dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY;
|
||||
_flags |= Simulation::DIRTY_LINEAR_VELOCITY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1744,7 +1745,7 @@ void EntityItem::setDamping(float value) {
|
|||
withWriteLock([&] {
|
||||
if (_damping != clampedDamping) {
|
||||
_damping = clampedDamping;
|
||||
_dirtyFlags |= Simulation::DIRTY_MATERIAL;
|
||||
_flags |= Simulation::DIRTY_MATERIAL;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1763,7 +1764,7 @@ void EntityItem::setGravity(const glm::vec3& value) {
|
|||
} else {
|
||||
_gravity = value;
|
||||
}
|
||||
_dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY;
|
||||
_flags |= Simulation::DIRTY_LINEAR_VELOCITY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1788,7 +1789,7 @@ void EntityItem::setAngularVelocity(const glm::vec3& value) {
|
|||
angularVelocity = value;
|
||||
}
|
||||
setLocalAngularVelocity(angularVelocity);
|
||||
_dirtyFlags |= Simulation::DIRTY_ANGULAR_VELOCITY;
|
||||
_flags |= Simulation::DIRTY_ANGULAR_VELOCITY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1799,7 +1800,7 @@ void EntityItem::setAngularDamping(float value) {
|
|||
withWriteLock([&] {
|
||||
if (_angularDamping != clampedDamping) {
|
||||
_angularDamping = clampedDamping;
|
||||
_dirtyFlags |= Simulation::DIRTY_MATERIAL;
|
||||
_flags |= Simulation::DIRTY_MATERIAL;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1808,7 +1809,7 @@ void EntityItem::setCollisionless(bool value) {
|
|||
withWriteLock([&] {
|
||||
if (_collisionless != value) {
|
||||
_collisionless = value;
|
||||
_dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP;
|
||||
_flags |= Simulation::DIRTY_COLLISION_GROUP;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1817,7 +1818,7 @@ void EntityItem::setCollisionMask(uint8_t value) {
|
|||
withWriteLock([&] {
|
||||
if ((_collisionMask & ENTITY_COLLISION_MASK_DEFAULT) != (value & ENTITY_COLLISION_MASK_DEFAULT)) {
|
||||
_collisionMask = (value & ENTITY_COLLISION_MASK_DEFAULT);
|
||||
_dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP;
|
||||
_flags |= Simulation::DIRTY_COLLISION_GROUP;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1829,11 +1830,11 @@ void EntityItem::setDynamic(bool value) {
|
|||
if (value && getShapeType() == SHAPE_TYPE_STATIC_MESH) {
|
||||
if (_dynamic) {
|
||||
_dynamic = false;
|
||||
_dirtyFlags |= Simulation::DIRTY_MOTION_TYPE;
|
||||
_flags |= Simulation::DIRTY_MOTION_TYPE;
|
||||
}
|
||||
} else {
|
||||
_dynamic = value;
|
||||
_dirtyFlags |= Simulation::DIRTY_MOTION_TYPE;
|
||||
_flags |= Simulation::DIRTY_MOTION_TYPE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1844,7 +1845,7 @@ void EntityItem::setRestitution(float value) {
|
|||
withWriteLock([&] {
|
||||
if (_restitution != clampedValue) {
|
||||
_restitution = clampedValue;
|
||||
_dirtyFlags |= Simulation::DIRTY_MATERIAL;
|
||||
_flags |= Simulation::DIRTY_MATERIAL;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1855,7 +1856,7 @@ void EntityItem::setFriction(float value) {
|
|||
withWriteLock([&] {
|
||||
if (_friction != clampedValue) {
|
||||
_friction = clampedValue;
|
||||
_dirtyFlags |= Simulation::DIRTY_MATERIAL;
|
||||
_flags |= Simulation::DIRTY_MATERIAL;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1864,7 +1865,7 @@ void EntityItem::setLifetime(float value) {
|
|||
withWriteLock([&] {
|
||||
if (_lifetime != value) {
|
||||
_lifetime = value;
|
||||
_dirtyFlags |= Simulation::DIRTY_LIFETIME;
|
||||
_flags |= Simulation::DIRTY_LIFETIME;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1873,7 +1874,7 @@ void EntityItem::setCreated(quint64 value) {
|
|||
withWriteLock([&] {
|
||||
if (_created != value) {
|
||||
_created = value;
|
||||
_dirtyFlags |= Simulation::DIRTY_LIFETIME;
|
||||
_flags |= Simulation::DIRTY_LIFETIME;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1902,7 +1903,7 @@ void EntityItem::computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask
|
|||
}
|
||||
}
|
||||
|
||||
if ((bool)(_dirtyFlags & Simulation::NO_BOOTSTRAPPING)) {
|
||||
if ((bool)(_flags & Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING)) {
|
||||
userMask &= ~USER_COLLISION_GROUP_MY_AVATAR;
|
||||
}
|
||||
mask = Physics::getDefaultCollisionMask(group) & (int16_t)(userMask);
|
||||
|
@ -1997,17 +1998,18 @@ bool EntityItem::addActionInternal(EntitySimulationPointer simulation, EntityDyn
|
|||
serializeActions(success, newDataCache);
|
||||
if (success) {
|
||||
_allActionsDataCache = newDataCache;
|
||||
_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
|
||||
_flags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
|
||||
|
||||
auto actionType = action->getType();
|
||||
if (actionType == DYNAMIC_TYPE_HOLD || actionType == DYNAMIC_TYPE_FAR_GRAB) {
|
||||
if (!(bool)(_dirtyFlags & Simulation::NO_BOOTSTRAPPING)) {
|
||||
_dirtyFlags |= Simulation::NO_BOOTSTRAPPING;
|
||||
_dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
|
||||
if (!(bool)(_flags & Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING)) {
|
||||
_flags |= Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING;
|
||||
_flags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
|
||||
forEachDescendant([&](SpatiallyNestablePointer child) {
|
||||
if (child->getNestableType() == NestableType::Entity) {
|
||||
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(child);
|
||||
entity->markDirtyFlags(Simulation::NO_BOOTSTRAPPING | Simulation::DIRTY_COLLISION_GROUP);
|
||||
entity->markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP);
|
||||
entity->markSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -2033,7 +2035,7 @@ bool EntityItem::updateAction(EntitySimulationPointer simulation, const QUuid& a
|
|||
if (success) {
|
||||
action->setIsMine(true);
|
||||
serializeActions(success, _allActionsDataCache);
|
||||
_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
|
||||
_flags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
|
||||
} else {
|
||||
qCDebug(entities) << "EntityItem::updateAction failed";
|
||||
}
|
||||
|
@ -2091,17 +2093,17 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi
|
|||
_objectActions.remove(actionID);
|
||||
|
||||
if ((removedActionType == DYNAMIC_TYPE_HOLD || removedActionType == DYNAMIC_TYPE_FAR_GRAB) && !stillHasGrabActions()) {
|
||||
_dirtyFlags &= ~Simulation::NO_BOOTSTRAPPING;
|
||||
_dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
|
||||
_flags &= ~Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING;
|
||||
_flags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
|
||||
forEachDescendant([&](SpatiallyNestablePointer child) {
|
||||
if (child->getNestableType() == NestableType::Entity) {
|
||||
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(child);
|
||||
entity->markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP);
|
||||
entity->clearDirtyFlags(Simulation::NO_BOOTSTRAPPING);
|
||||
entity->clearSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// NO-OP: we assume NO_BOOTSTRAPPING bits and collision group are correct
|
||||
// NO-OP: we assume SPECIAL_FLAGS_NO_BOOTSTRAPPING bits and collision group are correct
|
||||
// because they should have been set correctly when the action was added
|
||||
// and/or when children were linked
|
||||
}
|
||||
|
@ -2112,7 +2114,7 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi
|
|||
|
||||
bool success = true;
|
||||
serializeActions(success, _allActionsDataCache);
|
||||
_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
|
||||
_flags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
|
||||
setDynamicDataNeedsTransmit(true);
|
||||
return success;
|
||||
}
|
||||
|
@ -2132,8 +2134,8 @@ bool EntityItem::clearActions(EntitySimulationPointer simulation) {
|
|||
// empty _serializedActions means no actions for the EntityItem
|
||||
_actionsToRemove.clear();
|
||||
_allActionsDataCache.clear();
|
||||
_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
|
||||
_dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
|
||||
_flags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
|
||||
_flags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
@ -2364,7 +2366,7 @@ QList<EntityDynamicPointer> EntityItem::getActionsOfType(EntityDynamicType typeT
|
|||
void EntityItem::locationChanged(bool tellPhysics) {
|
||||
requiresRecalcBoxes();
|
||||
if (tellPhysics) {
|
||||
_dirtyFlags |= Simulation::DIRTY_TRANSFORM;
|
||||
_flags |= Simulation::DIRTY_TRANSFORM;
|
||||
EntityTreePointer tree = getTree();
|
||||
if (tree) {
|
||||
tree->entityChanged(getThisPointer());
|
||||
|
@ -2832,7 +2834,7 @@ DEFINE_PROPERTY_ACCESSOR(quint32, StaticCertificateVersion, staticCertificateVer
|
|||
uint32_t EntityItem::getDirtyFlags() const {
|
||||
uint32_t result;
|
||||
withReadLock([&] {
|
||||
result = _dirtyFlags;
|
||||
result = _flags & Simulation::DIRTY_FLAGS;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
@ -2840,13 +2842,37 @@ uint32_t EntityItem::getDirtyFlags() const {
|
|||
|
||||
void EntityItem::markDirtyFlags(uint32_t mask) {
|
||||
withWriteLock([&] {
|
||||
_dirtyFlags |= mask;
|
||||
mask &= Simulation::DIRTY_FLAGS;
|
||||
_flags |= mask;
|
||||
});
|
||||
}
|
||||
|
||||
void EntityItem::clearDirtyFlags(uint32_t mask) {
|
||||
withWriteLock([&] {
|
||||
_dirtyFlags &= ~mask;
|
||||
mask &= Simulation::DIRTY_FLAGS;
|
||||
_flags &= ~mask;
|
||||
});
|
||||
}
|
||||
|
||||
uint32_t EntityItem::getSpecialFlags() const {
|
||||
uint32_t result;
|
||||
withReadLock([&] {
|
||||
result = _flags & Simulation::SPECIAL_FLAGS;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void EntityItem::markSpecialFlags(uint32_t mask) {
|
||||
withWriteLock([&] {
|
||||
mask &= Simulation::SPECIAL_FLAGS;
|
||||
_flags |= mask;
|
||||
});
|
||||
}
|
||||
|
||||
void EntityItem::clearSpecialFlags(uint32_t mask) {
|
||||
withWriteLock([&] {
|
||||
mask &= Simulation::SPECIAL_FLAGS;
|
||||
_flags &= ~mask;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -358,7 +358,11 @@ public:
|
|||
|
||||
uint32_t getDirtyFlags() const;
|
||||
void markDirtyFlags(uint32_t mask);
|
||||
void clearDirtyFlags(uint32_t mask = 0xffffffff);
|
||||
void clearDirtyFlags(uint32_t mask = 0x0000ffff);
|
||||
|
||||
uint32_t getSpecialFlags() const;
|
||||
void markSpecialFlags(uint32_t mask);
|
||||
void clearSpecialFlags(uint32_t mask = 0xffff0000);
|
||||
|
||||
bool isMoving() const;
|
||||
bool isMovingRelativeToParent() const;
|
||||
|
@ -385,7 +389,7 @@ public:
|
|||
void getAllTerseUpdateProperties(EntityItemProperties& properties) const;
|
||||
|
||||
void flagForOwnershipBid(uint8_t priority);
|
||||
void flagForMotionStateChange() { _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; }
|
||||
void flagForMotionStateChange() { _flags |= Simulation::DIRTY_MOTION_TYPE; }
|
||||
|
||||
QString actionsToDebugString();
|
||||
bool addAction(EntitySimulationPointer simulation, EntityDynamicPointer action);
|
||||
|
@ -575,7 +579,7 @@ protected:
|
|||
//
|
||||
|
||||
// DirtyFlags are set whenever a property changes that the EntitySimulation needs to know about.
|
||||
uint32_t _dirtyFlags { 0 }; // things that have changed from EXTERNAL changes (via script or packet) but NOT from simulation
|
||||
uint32_t _flags { 0 }; // things that have changed from EXTERNAL changes (via script or packet) but NOT from simulation
|
||||
|
||||
// these backpointers are only ever set/cleared by friends:
|
||||
EntityTreeElementPointer _element; // set by EntityTreeElement
|
||||
|
|
|
@ -85,7 +85,7 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) {
|
|||
bool somethingChangedInAnimations = _animationProperties.setProperties(properties);
|
||||
|
||||
if (somethingChangedInAnimations) {
|
||||
_dirtyFlags |= Simulation::DIRTY_UPDATEABLE;
|
||||
_flags |= Simulation::DIRTY_UPDATEABLE;
|
||||
}
|
||||
somethingChanged = somethingChanged || somethingChangedInAnimations;
|
||||
|
||||
|
@ -132,7 +132,7 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
|
|||
READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType);
|
||||
|
||||
if (animationPropertiesChanged) {
|
||||
_dirtyFlags |= Simulation::DIRTY_UPDATEABLE;
|
||||
_flags |= Simulation::DIRTY_UPDATEABLE;
|
||||
somethingChanged = true;
|
||||
}
|
||||
|
||||
|
@ -305,10 +305,10 @@ void ModelEntityItem::setShapeType(ShapeType type) {
|
|||
// dynamic and STATIC_MESH are incompatible
|
||||
// since the shape is being set here we clear the dynamic bit
|
||||
_dynamic = false;
|
||||
_dirtyFlags |= Simulation::DIRTY_MOTION_TYPE;
|
||||
_flags |= Simulation::DIRTY_MOTION_TYPE;
|
||||
}
|
||||
_shapeType = type;
|
||||
_dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
|
||||
_flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -336,7 +336,7 @@ void ModelEntityItem::setModelURL(const QString& url) {
|
|||
if (_modelURL != url) {
|
||||
_modelURL = url;
|
||||
if (_shapeType == SHAPE_TYPE_STATIC_MESH) {
|
||||
_dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
|
||||
_flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -348,14 +348,14 @@ void ModelEntityItem::setCompoundShapeURL(const QString& url) {
|
|||
ShapeType oldType = computeTrueShapeType();
|
||||
_compoundShapeURL.set(url);
|
||||
if (oldType != computeTrueShapeType()) {
|
||||
_dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
|
||||
_flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ModelEntityItem::setAnimationURL(const QString& url) {
|
||||
_dirtyFlags |= Simulation::DIRTY_UPDATEABLE;
|
||||
_flags |= Simulation::DIRTY_UPDATEABLE;
|
||||
withWriteLock([&] {
|
||||
_animationProperties.setURL(url);
|
||||
});
|
||||
|
@ -422,16 +422,16 @@ void ModelEntityItem::setAnimationSettings(const QString& value) {
|
|||
bool allowTranslation = settingsMap["allowTranslation"].toBool();
|
||||
setAnimationAllowTranslation(allowTranslation);
|
||||
}
|
||||
_dirtyFlags |= Simulation::DIRTY_UPDATEABLE;
|
||||
_flags |= Simulation::DIRTY_UPDATEABLE;
|
||||
}
|
||||
|
||||
void ModelEntityItem::setAnimationIsPlaying(bool value) {
|
||||
_dirtyFlags |= Simulation::DIRTY_UPDATEABLE;
|
||||
_flags |= Simulation::DIRTY_UPDATEABLE;
|
||||
_animationProperties.setRunning(value);
|
||||
}
|
||||
|
||||
void ModelEntityItem::setAnimationFPS(float value) {
|
||||
_dirtyFlags |= Simulation::DIRTY_UPDATEABLE;
|
||||
_flags |= Simulation::DIRTY_UPDATEABLE;
|
||||
_animationProperties.setFPS(value);
|
||||
}
|
||||
|
||||
|
|
|
@ -601,7 +601,7 @@ void ParticleEffectEntityItem::setShapeType(ShapeType type) {
|
|||
withWriteLock([&] {
|
||||
if (type != _shapeType) {
|
||||
_shapeType = type;
|
||||
_dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
|
||||
_flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -27,10 +27,28 @@ namespace Simulation {
|
|||
const uint32_t DIRTY_PHYSICS_ACTIVATION = 0x0800; // should activate object in physics engine
|
||||
const uint32_t DIRTY_SIMULATOR_ID = 0x1000; // the simulatorID has changed
|
||||
const uint32_t DIRTY_SIMULATION_OWNERSHIP_PRIORITY = 0x2000; // our own bid priority has changed
|
||||
const uint32_t NO_BOOTSTRAPPING = 0x4000;
|
||||
|
||||
// bits 17-32 are reservied for special flags
|
||||
const uint32_t SPECIAL_FLAGS_NO_BOOTSTRAPPING = 0x10000;
|
||||
|
||||
const uint32_t DIRTY_TRANSFORM = DIRTY_POSITION | DIRTY_ROTATION;
|
||||
const uint32_t DIRTY_VELOCITIES = DIRTY_LINEAR_VELOCITY | DIRTY_ANGULAR_VELOCITY;
|
||||
const uint32_t SPECIAL_FLAGS = SPECIAL_FLAGS_NO_BOOTSTRAPPING;
|
||||
|
||||
const uint32_t DIRTY_FLAGS = DIRTY_POSITION |
|
||||
DIRTY_ROTATION |
|
||||
DIRTY_LINEAR_VELOCITY |
|
||||
DIRTY_ANGULAR_VELOCITY |
|
||||
DIRTY_MASS |
|
||||
DIRTY_COLLISION_GROUP |
|
||||
DIRTY_MOTION_TYPE |
|
||||
DIRTY_SHAPE |
|
||||
DIRTY_LIFETIME |
|
||||
DIRTY_UPDATEABLE |
|
||||
DIRTY_MATERIAL |
|
||||
DIRTY_PHYSICS_ACTIVATION |
|
||||
DIRTY_SIMULATOR_ID |
|
||||
DIRTY_SIMULATION_OWNERSHIP_PRIORITY;
|
||||
};
|
||||
|
||||
#endif // hifi_SimulationFlags_h
|
||||
|
|
|
@ -6,9 +6,9 @@ namespace gl {
|
|||
|
||||
|
||||
#ifdef SEPARATE_PROGRAM
|
||||
bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject, std::string& error) {
|
||||
bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject, std::string& message) {
|
||||
#else
|
||||
bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, std::string& error) {
|
||||
bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, std::string& message) {
|
||||
#endif
|
||||
if (shaderSource.empty()) {
|
||||
qCDebug(glLogging) << "GLShader::compileShader - no GLSL shader source code ? so failed to create";
|
||||
|
@ -34,52 +34,57 @@ namespace gl {
|
|||
GLint compiled = 0;
|
||||
glGetShaderiv(glshader, GL_COMPILE_STATUS, &compiled);
|
||||
|
||||
// if compilation fails
|
||||
if (!compiled) {
|
||||
|
||||
// save the source code to a temp file so we can debug easily
|
||||
/*
|
||||
std::ofstream filestream;
|
||||
filestream.open("debugshader.glsl");
|
||||
if (filestream.is_open()) {
|
||||
filestream << srcstr[0];
|
||||
filestream << srcstr[1];
|
||||
filestream.close();
|
||||
}
|
||||
*/
|
||||
|
||||
GLint infoLength = 0;
|
||||
glGetShaderiv(glshader, GL_INFO_LOG_LENGTH, &infoLength);
|
||||
GLint infoLength = 0;
|
||||
glGetShaderiv(glshader, GL_INFO_LOG_LENGTH, &infoLength);
|
||||
|
||||
if ((infoLength > 0) || !compiled) {
|
||||
char* temp = new char[infoLength];
|
||||
glGetShaderInfoLog(glshader, infoLength, NULL, temp);
|
||||
|
||||
message = std::string(temp);
|
||||
|
||||
/*
|
||||
filestream.open("debugshader.glsl.info.txt");
|
||||
if (filestream.is_open()) {
|
||||
filestream << std::string(temp);
|
||||
filestream.close();
|
||||
}
|
||||
*/
|
||||
|
||||
qCCritical(glLogging) << "GLShader::compileShader - failed to compile the gl shader object:";
|
||||
int lineNumber = 0;
|
||||
for (auto s : srcstr) {
|
||||
QString str(s);
|
||||
QStringList lines = str.split("\n");
|
||||
for (auto& line : lines) {
|
||||
qCCritical(glLogging).noquote() << QString("%1: %2").arg(lineNumber++, 5, 10, QChar('0')).arg(line);
|
||||
// if compilation fails
|
||||
if (!compiled) {
|
||||
// save the source code to a temp file so we can debug easily
|
||||
/*
|
||||
std::ofstream filestream;
|
||||
filestream.open("debugshader.glsl");
|
||||
if (filestream.is_open()) {
|
||||
filestream << srcstr[0];
|
||||
filestream << srcstr[1];
|
||||
filestream.close();
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
filestream.open("debugshader.glsl.info.txt");
|
||||
if (filestream.is_open()) {
|
||||
filestream << std::string(temp);
|
||||
filestream.close();
|
||||
}
|
||||
*/
|
||||
|
||||
qCCritical(glLogging) << "GLShader::compileShader - failed to compile the gl shader object:";
|
||||
int lineNumber = 0;
|
||||
for (auto s : srcstr) {
|
||||
QString str(s);
|
||||
QStringList lines = str.split("\n");
|
||||
for (auto& line : lines) {
|
||||
qCCritical(glLogging).noquote() << QString("%1: %2").arg(lineNumber++, 5, 10, QChar('0')).arg(line);
|
||||
}
|
||||
}
|
||||
qCCritical(glLogging) << "GLShader::compileShader - errors:";
|
||||
qCCritical(glLogging) << temp;
|
||||
|
||||
delete[] temp;
|
||||
glDeleteShader(glshader);
|
||||
return false;
|
||||
}
|
||||
qCCritical(glLogging) << "GLShader::compileShader - errors:";
|
||||
qCCritical(glLogging) << temp;
|
||||
|
||||
error = std::string(temp);
|
||||
// Compilation success
|
||||
qCWarning(glLogging) << "GLShader::compileShader - Success:";
|
||||
qCWarning(glLogging) << temp;
|
||||
delete[] temp;
|
||||
|
||||
glDeleteShader(glshader);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef SEPARATE_PROGRAM
|
||||
|
@ -137,7 +142,7 @@ namespace gl {
|
|||
return true;
|
||||
}
|
||||
|
||||
GLuint compileProgram(const std::vector<GLuint>& glshaders, std::string& error) {
|
||||
GLuint compileProgram(const std::vector<GLuint>& glshaders, std::string& message, std::vector<GLchar>& binary) {
|
||||
// A brand new program:
|
||||
GLuint glprogram = glCreateProgram();
|
||||
if (!glprogram) {
|
||||
|
@ -157,39 +162,65 @@ GLuint compileProgram(const std::vector<GLuint>& glshaders, std::string& error)
|
|||
GLint linked = 0;
|
||||
glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
|
||||
|
||||
if (!linked) {
|
||||
/*
|
||||
// save the source code to a temp file so we can debug easily
|
||||
std::ofstream filestream;
|
||||
filestream.open("debugshader.glsl");
|
||||
if (filestream.is_open()) {
|
||||
filestream << shaderSource->source;
|
||||
filestream.close();
|
||||
}
|
||||
*/
|
||||
|
||||
GLint infoLength = 0;
|
||||
glGetProgramiv(glprogram, GL_INFO_LOG_LENGTH, &infoLength);
|
||||
GLint infoLength = 0;
|
||||
glGetProgramiv(glprogram, GL_INFO_LOG_LENGTH, &infoLength);
|
||||
|
||||
if ((infoLength > 0) || !linked) {
|
||||
char* temp = new char[infoLength];
|
||||
glGetProgramInfoLog(glprogram, infoLength, NULL, temp);
|
||||
|
||||
qCDebug(glLogging) << "GLShader::compileProgram - failed to LINK the gl program object :";
|
||||
qCDebug(glLogging) << temp;
|
||||
message = std::string(temp);
|
||||
|
||||
error = std::string(temp);
|
||||
delete[] temp;
|
||||
if (!linked) {
|
||||
/*
|
||||
// save the source code to a temp file so we can debug easily
|
||||
std::ofstream filestream;
|
||||
filestream.open("debugshader.glsl");
|
||||
if (filestream.is_open()) {
|
||||
filestream << shaderSource->source;
|
||||
filestream.close();
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
filestream.open("debugshader.glsl.info.txt");
|
||||
if (filestream.is_open()) {
|
||||
filestream << std::string(temp);
|
||||
filestream.close();
|
||||
qCDebug(glLogging) << "GLShader::compileProgram - failed to LINK the gl program object :";
|
||||
qCDebug(glLogging) << temp;
|
||||
|
||||
delete[] temp;
|
||||
|
||||
/*
|
||||
filestream.open("debugshader.glsl.info.txt");
|
||||
if (filestream.is_open()) {
|
||||
filestream << std::string(temp);
|
||||
filestream.close();
|
||||
}
|
||||
*/
|
||||
|
||||
glDeleteProgram(glprogram);
|
||||
return 0;
|
||||
} else {
|
||||
qCDebug(glLogging) << "GLShader::compileProgram - success:";
|
||||
qCDebug(glLogging) << temp;
|
||||
delete[] temp;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
glDeleteProgram(glprogram);
|
||||
return 0;
|
||||
// If linked get the binaries
|
||||
if (linked) {
|
||||
GLint binaryLength = 0;
|
||||
glGetProgramiv(glprogram, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
|
||||
|
||||
if (binaryLength > 0) {
|
||||
GLint numBinFormats = 0;
|
||||
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &numBinFormats);
|
||||
if (numBinFormats > 0) {
|
||||
binary.resize(binaryLength);
|
||||
std::vector<GLint> binFormats(numBinFormats);
|
||||
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, binFormats.data());
|
||||
|
||||
GLenum programBinFormat;
|
||||
glGetProgramBinary(glprogram, binaryLength, NULL, &programBinFormat, binary.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return glprogram;
|
||||
|
|
|
@ -17,12 +17,12 @@
|
|||
|
||||
namespace gl {
|
||||
#ifdef SEPARATE_PROGRAM
|
||||
bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject, std::string& error);
|
||||
bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject, std::string& message);
|
||||
#else
|
||||
bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, std::string& error);
|
||||
bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, std::string& message);
|
||||
#endif
|
||||
|
||||
GLuint compileProgram(const std::vector<GLuint>& glshaders, std::string& error);
|
||||
GLuint compileProgram(const std::vector<GLuint>& glshaders, std::string& message, std::vector<GLchar>& binary);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -68,8 +68,8 @@ GLBackend& getBackend() {
|
|||
return *INSTANCE;
|
||||
}
|
||||
|
||||
bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings) {
|
||||
return GLShader::makeProgram(getBackend(), shader, slotBindings);
|
||||
bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler) {
|
||||
return GLShader::makeProgram(getBackend(), shader, slotBindings, handler);
|
||||
}
|
||||
|
||||
GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
||||
|
|
|
@ -64,7 +64,7 @@ protected:
|
|||
explicit GLBackend(bool syncCache);
|
||||
GLBackend();
|
||||
public:
|
||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings = Shader::BindingSet());
|
||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler);
|
||||
|
||||
virtual ~GLBackend();
|
||||
|
||||
|
@ -423,8 +423,8 @@ protected:
|
|||
} _pipeline;
|
||||
|
||||
// Backend dependant compilation of the shader
|
||||
virtual GLShader* compileBackendProgram(const Shader& program);
|
||||
virtual GLShader* compileBackendShader(const Shader& shader);
|
||||
virtual GLShader* compileBackendProgram(const Shader& program, const Shader::CompilationHandler& handler);
|
||||
virtual GLShader* compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler);
|
||||
virtual std::string getBackendShaderHeader() const;
|
||||
virtual void makeProgramBindings(ShaderObject& shaderObject);
|
||||
class ElementResource {
|
||||
|
|
|
@ -56,28 +56,47 @@ static const std::array<std::string, GLShader::NumVersions> VERSION_DEFINES { {
|
|||
stereoVersion
|
||||
} };
|
||||
|
||||
GLShader* GLBackend::compileBackendShader(const Shader& shader) {
|
||||
GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler) {
|
||||
// Any GLSLprogram ? normally yes...
|
||||
const std::string& shaderSource = shader.getSource().getCode();
|
||||
GLenum shaderDomain = SHADER_DOMAINS[shader.getType()];
|
||||
GLShader::ShaderObjects shaderObjects;
|
||||
Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
|
||||
shader.incrementCompilationAttempt();
|
||||
|
||||
for (int version = 0; version < GLShader::NumVersions; version++) {
|
||||
auto& shaderObject = shaderObjects[version];
|
||||
|
||||
std::string shaderDefines = getBackendShaderHeader() + "\n" + DOMAIN_DEFINES[shader.getType()] + "\n" + VERSION_DEFINES[version];
|
||||
std::string error;
|
||||
if (handler) {
|
||||
bool retest = true;
|
||||
std::string currentSrc = shaderSource;
|
||||
// When a Handler is specified, we can try multiple times to build the shader and let the handler change the source if the compilation fails.
|
||||
// The retest bool is set to false as soon as the compilation succeed to wexit the while loop.
|
||||
// The handler tells us if we should retry or not while returning a modified version of the source.
|
||||
while (retest) {
|
||||
bool result = ::gl::compileShader(shaderDomain, currentSrc, shaderDefines, shaderObject.glshader, compilationLogs[version].message);
|
||||
compilationLogs[version].compiled = result;
|
||||
if (!result) {
|
||||
std::string newSrc;
|
||||
retest = handler(shader, currentSrc, compilationLogs[version], newSrc);
|
||||
currentSrc = newSrc;
|
||||
} else {
|
||||
retest = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
compilationLogs[version].compiled = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, compilationLogs[version].message);
|
||||
}
|
||||
|
||||
#ifdef SEPARATE_PROGRAM
|
||||
bool result = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, shaderObject.glprogram, error);
|
||||
#else
|
||||
bool result = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, error);
|
||||
#endif
|
||||
if (!result) {
|
||||
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << error.c_str();
|
||||
if (!compilationLogs[version].compiled) {
|
||||
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << compilationLogs[version].message.c_str();
|
||||
shader.setCompilationLogs(compilationLogs);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
// Compilation feedback
|
||||
shader.setCompilationLogs(compilationLogs);
|
||||
|
||||
// So far so good, the shader is created successfully
|
||||
GLShader* object = new GLShader(this->shared_from_this());
|
||||
|
@ -86,39 +105,47 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader) {
|
|||
return object;
|
||||
}
|
||||
|
||||
GLShader* GLBackend::compileBackendProgram(const Shader& program) {
|
||||
GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader::CompilationHandler& handler) {
|
||||
if (!program.isProgram()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GLShader::ShaderObjects programObjects;
|
||||
|
||||
program.incrementCompilationAttempt();
|
||||
Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
|
||||
|
||||
for (int version = 0; version < GLShader::NumVersions; version++) {
|
||||
auto& programObject = programObjects[version];
|
||||
|
||||
// Let's go through every shaders and make sure they are ready to go
|
||||
std::vector< GLuint > shaderGLObjects;
|
||||
for (auto subShader : program.getShaders()) {
|
||||
auto object = GLShader::sync((*this), *subShader);
|
||||
auto object = GLShader::sync((*this), *subShader, handler);
|
||||
if (object) {
|
||||
shaderGLObjects.push_back(object->_shaderObjects[version].glshader);
|
||||
} else {
|
||||
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - One of the shaders of the program is not compiled?";
|
||||
compilationLogs[version].compiled = false;
|
||||
compilationLogs[version].message = std::string("Failed to compile, one of the shaders of the program is not compiled ?");
|
||||
program.setCompilationLogs(compilationLogs);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::string error;
|
||||
GLuint glprogram = ::gl::compileProgram(shaderGLObjects, error);
|
||||
GLuint glprogram = ::gl::compileProgram(shaderGLObjects, compilationLogs[version].message, compilationLogs[version].binary);
|
||||
if (glprogram == 0) {
|
||||
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << error.c_str();
|
||||
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << compilationLogs[version].message.c_str();
|
||||
program.setCompilationLogs(compilationLogs);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
compilationLogs[version].compiled = true;
|
||||
programObject.glprogram = glprogram;
|
||||
|
||||
makeProgramBindings(programObject);
|
||||
}
|
||||
// Compilation feedback
|
||||
program.setCompilationLogs(compilationLogs);
|
||||
|
||||
// So far so good, the program versions have all been created successfully
|
||||
GLShader* object = new GLShader(this->shared_from_this());
|
||||
|
|
|
@ -30,7 +30,7 @@ GLShader::~GLShader() {
|
|||
}
|
||||
}
|
||||
|
||||
GLShader* GLShader::sync(GLBackend& backend, const Shader& shader) {
|
||||
GLShader* GLShader::sync(GLBackend& backend, const Shader& shader, const Shader::CompilationHandler& handler) {
|
||||
GLShader* object = Backend::getGPUObject<GLShader>(shader);
|
||||
|
||||
// If GPU object already created then good
|
||||
|
@ -39,13 +39,13 @@ GLShader* GLShader::sync(GLBackend& backend, const Shader& shader) {
|
|||
}
|
||||
// need to have a gpu object?
|
||||
if (shader.isProgram()) {
|
||||
GLShader* tempObject = backend.compileBackendProgram(shader);
|
||||
GLShader* tempObject = backend.compileBackendProgram(shader, handler);
|
||||
if (tempObject) {
|
||||
object = tempObject;
|
||||
Backend::setGPUObject(shader, object);
|
||||
}
|
||||
} else if (shader.isDomain()) {
|
||||
GLShader* tempObject = backend.compileBackendShader(shader);
|
||||
GLShader* tempObject = backend.compileBackendShader(shader, handler);
|
||||
if (tempObject) {
|
||||
object = tempObject;
|
||||
Backend::setGPUObject(shader, object);
|
||||
|
@ -56,10 +56,10 @@ GLShader* GLShader::sync(GLBackend& backend, const Shader& shader) {
|
|||
return object;
|
||||
}
|
||||
|
||||
bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings) {
|
||||
bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler) {
|
||||
|
||||
// First make sure the Shader has been compiled
|
||||
GLShader* object = sync(backend, shader);
|
||||
GLShader* object = sync(backend, shader, handler);
|
||||
if (!object) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -21,8 +21,8 @@ struct ShaderObject {
|
|||
|
||||
class GLShader : public GPUObject {
|
||||
public:
|
||||
static GLShader* sync(GLBackend& backend, const Shader& shader);
|
||||
static bool makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings);
|
||||
static GLShader* sync(GLBackend& backend, const Shader& shader, const Shader::CompilationHandler& handler = nullptr);
|
||||
static bool makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler);
|
||||
|
||||
enum Version {
|
||||
Mono = 0,
|
||||
|
|
|
@ -61,8 +61,8 @@ GLBackend& getBackend() {
|
|||
return *INSTANCE;
|
||||
}
|
||||
|
||||
bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings) {
|
||||
return GLShader::makeProgram(getBackend(), shader, slotBindings);
|
||||
bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler) {
|
||||
return GLShader::makeProgram(getBackend(), shader, slotBindings, handler);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ protected:
|
|||
explicit GLBackend(bool syncCache);
|
||||
GLBackend();
|
||||
public:
|
||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings = Shader::BindingSet());
|
||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings = Shader::BindingSet(), const Shader::CompilationHandler& handler = nullptr);
|
||||
|
||||
virtual ~GLBackend();
|
||||
|
||||
|
@ -420,8 +420,8 @@ protected:
|
|||
} _pipeline;
|
||||
|
||||
// Backend dependant compilation of the shader
|
||||
virtual GLShader* compileBackendProgram(const Shader& program);
|
||||
virtual GLShader* compileBackendShader(const Shader& shader);
|
||||
virtual GLShader* compileBackendProgram(const Shader& program, const Shader::CompilationHandler& handler);
|
||||
virtual GLShader* compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler);
|
||||
virtual std::string getBackendShaderHeader() const;
|
||||
virtual void makeProgramBindings(ShaderObject& shaderObject);
|
||||
class ElementResource {
|
||||
|
|
|
@ -56,32 +56,50 @@ static const std::array<std::string, GLShader::NumVersions> VERSION_DEFINES { {
|
|||
stereoVersion
|
||||
} };
|
||||
|
||||
GLShader* GLBackend::compileBackendShader(const Shader& shader) {
|
||||
GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler) {
|
||||
// Any GLSLprogram ? normally yes...
|
||||
const std::string& shaderSource = shader.getSource().getCode();
|
||||
GLenum shaderDomain = SHADER_DOMAINS[shader.getType()];
|
||||
GLShader::ShaderObjects shaderObjects;
|
||||
Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
|
||||
|
||||
for (int version = 0; version < GLShader::NumVersions; version++) {
|
||||
auto& shaderObject = shaderObjects[version];
|
||||
|
||||
std::string shaderDefines = getBackendShaderHeader() + "\n" + DOMAIN_DEFINES[shader.getType()] + "\n" + VERSION_DEFINES[version]
|
||||
+ "\n#extension GL_EXT_texture_buffer : enable"
|
||||
+ "\nprecision lowp float; // check precision 2"
|
||||
+ "\nprecision lowp samplerBuffer;"
|
||||
+ "\nprecision lowp sampler2DShadow;";
|
||||
std::string error;
|
||||
+ "\n#extension GL_EXT_texture_buffer : enable"
|
||||
+ "\nprecision lowp float; // check precision 2"
|
||||
+ "\nprecision lowp samplerBuffer;"
|
||||
+ "\nprecision lowp sampler2DShadow;";
|
||||
if (handler) {
|
||||
bool retest = true;
|
||||
std::string currentSrc = shaderSource;
|
||||
// When a Handler is specified, we can try multiple times to build the shader and let the handler change the source if the compilation fails.
|
||||
// The retest bool is set to false as soon as the compilation succeed to wexit the while loop.
|
||||
// The handler tells us if we should retry or not while returning a modified version of the source.
|
||||
while (retest) {
|
||||
bool result = ::gl::compileShader(shaderDomain, currentSrc, shaderDefines, shaderObject.glshader, compilationLogs[version].message);
|
||||
compilationLogs[version].compiled = result;
|
||||
if (!result) {
|
||||
std::string newSrc;
|
||||
retest = handler(shader, currentSrc, compilationLogs[version], newSrc);
|
||||
currentSrc = newSrc;
|
||||
} else {
|
||||
retest = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
compilationLogs[version].compiled = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, compilationLogs[version].message);
|
||||
}
|
||||
|
||||
#ifdef SEPARATE_PROGRAM
|
||||
bool result = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, shaderObject.glprogram, error);
|
||||
#else
|
||||
bool result = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, error);
|
||||
#endif
|
||||
if (!result) {
|
||||
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << error.c_str();
|
||||
if (!compilationLogs[version].compiled) {
|
||||
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << compilationLogs[version].message.c_str();
|
||||
shader.setCompilationLogs(compilationLogs);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
// Compilation feedback
|
||||
shader.setCompilationLogs(compilationLogs);
|
||||
|
||||
// So far so good, the shader is created successfully
|
||||
GLShader* object = new GLShader(this->shared_from_this());
|
||||
|
@ -90,32 +108,35 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader) {
|
|||
return object;
|
||||
}
|
||||
|
||||
GLShader* GLBackend::compileBackendProgram(const Shader& program) {
|
||||
GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader::CompilationHandler& handler) {
|
||||
if (!program.isProgram()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GLShader::ShaderObjects programObjects;
|
||||
|
||||
Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
|
||||
|
||||
for (int version = 0; version < GLShader::NumVersions; version++) {
|
||||
auto& programObject = programObjects[version];
|
||||
|
||||
// Let's go through every shaders and make sure they are ready to go
|
||||
std::vector<GLuint> shaderGLObjects;
|
||||
std::vector< GLuint > shaderGLObjects;
|
||||
for (auto subShader : program.getShaders()) {
|
||||
auto object = GLShader::sync((*this), *subShader);
|
||||
auto object = GLShader::sync((*this), *subShader, handler);
|
||||
if (object) {
|
||||
shaderGLObjects.push_back(object->_shaderObjects[version].glshader);
|
||||
} else {
|
||||
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - One of the shaders of the program is not compiled?";
|
||||
program.setCompilationLogs(compilationLogs);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::string error;
|
||||
GLuint glprogram = ::gl::compileProgram(shaderGLObjects, error);
|
||||
GLuint glprogram = ::gl::compileProgram(shaderGLObjects, compilationLogs[version].message, compilationLogs[version].binary);
|
||||
if (glprogram == 0) {
|
||||
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << error.c_str();
|
||||
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << compilationLogs[version].message.c_str();
|
||||
program.setCompilationLogs(compilationLogs);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -123,6 +144,8 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program) {
|
|||
|
||||
makeProgramBindings(programObject);
|
||||
}
|
||||
// Compilation feedback
|
||||
program.setCompilationLogs(compilationLogs);
|
||||
|
||||
// So far so good, the program versions have all been created successfully
|
||||
GLShader* object = new GLShader(this->shared_from_this());
|
||||
|
|
|
@ -30,7 +30,7 @@ GLShader::~GLShader() {
|
|||
}
|
||||
}
|
||||
|
||||
GLShader* GLShader::sync(GLBackend& backend, const Shader& shader) {
|
||||
GLShader* GLShader::sync(GLBackend& backend, const Shader& shader, const Shader::CompilationHandler& handler) {
|
||||
GLShader* object = Backend::getGPUObject<GLShader>(shader);
|
||||
|
||||
// If GPU object already created then good
|
||||
|
@ -39,13 +39,13 @@ GLShader* GLShader::sync(GLBackend& backend, const Shader& shader) {
|
|||
}
|
||||
// need to have a gpu object?
|
||||
if (shader.isProgram()) {
|
||||
GLShader* tempObject = backend.compileBackendProgram(shader);
|
||||
GLShader* tempObject = backend.compileBackendProgram(shader, handler);
|
||||
if (tempObject) {
|
||||
object = tempObject;
|
||||
Backend::setGPUObject(shader, object);
|
||||
}
|
||||
} else if (shader.isDomain()) {
|
||||
GLShader* tempObject = backend.compileBackendShader(shader);
|
||||
GLShader* tempObject = backend.compileBackendShader(shader, handler);
|
||||
if (tempObject) {
|
||||
object = tempObject;
|
||||
Backend::setGPUObject(shader, object);
|
||||
|
@ -56,10 +56,10 @@ GLShader* GLShader::sync(GLBackend& backend, const Shader& shader) {
|
|||
return object;
|
||||
}
|
||||
|
||||
bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings) {
|
||||
bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler) {
|
||||
|
||||
// First make sure the Shader has been compiled
|
||||
GLShader* object = sync(backend, shader);
|
||||
GLShader* object = sync(backend, shader, handler);
|
||||
if (!object) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -21,8 +21,8 @@ struct ShaderObject {
|
|||
|
||||
class GLShader : public GPUObject {
|
||||
public:
|
||||
static GLShader* sync(GLBackend& backend, const Shader& shader);
|
||||
static bool makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings);
|
||||
static GLShader* sync(GLBackend& backend, const Shader& shader, const Shader::CompilationHandler& handler = nullptr);
|
||||
static bool makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler = nullptr);
|
||||
|
||||
enum Version {
|
||||
Mono = 0,
|
||||
|
|
|
@ -127,7 +127,7 @@ void Context::executeFrame(const FramePointer& frame) const {
|
|||
_frameStats.evalDelta(beginStats, endStats);
|
||||
}
|
||||
|
||||
bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings) {
|
||||
bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings, const Shader::CompilationHandler& handler) {
|
||||
// If we're running in another DLL context, we need to fetch the program callback out of the application
|
||||
// FIXME find a way to do this without reliance on Qt app properties
|
||||
if (!_makeProgramCallback) {
|
||||
|
@ -135,7 +135,7 @@ bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings) {
|
|||
_makeProgramCallback = reinterpret_cast<Context::MakeProgram>(rawCallback);
|
||||
}
|
||||
if (shader.isProgram() && _makeProgramCallback) {
|
||||
return _makeProgramCallback(shader, bindings);
|
||||
return _makeProgramCallback(shader, bindings, handler);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -143,7 +143,7 @@ class Context {
|
|||
public:
|
||||
using Size = Resource::Size;
|
||||
typedef BackendPointer (*CreateBackend)();
|
||||
typedef bool (*MakeProgram)(Shader& shader, const Shader::BindingSet& bindings);
|
||||
typedef bool (*MakeProgram)(Shader& shader, const Shader::BindingSet& bindings, const Shader::CompilationHandler& handler);
|
||||
|
||||
|
||||
// This one call must happen before any context is created or used (Shader::MakeProgram) in order to setup the Backend and any singleton data needed
|
||||
|
@ -262,7 +262,7 @@ protected:
|
|||
// makeProgramShader(...) make a program shader ready to be used in a Batch.
|
||||
// It compiles the sub shaders, link them and defines the Slots and their bindings.
|
||||
// If the shader passed is not a program, nothing happens.
|
||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings);
|
||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings, const Shader::CompilationHandler& handler);
|
||||
|
||||
static CreateBackend _createBackendCallback;
|
||||
static MakeProgram _makeProgramCallback;
|
||||
|
|
|
@ -17,59 +17,111 @@
|
|||
|
||||
using namespace gpu;
|
||||
|
||||
Shader::Shader(Type type, const Source& source):
|
||||
std::atomic<uint32_t> Shader::_nextShaderID( 1 );
|
||||
Shader::DomainShaderMaps Shader::_domainShaderMaps;
|
||||
Shader::ProgramMap Shader::_programMap;
|
||||
|
||||
|
||||
Shader::Shader(Type type, const Source& source) :
|
||||
_source(source),
|
||||
_type(type)
|
||||
_type(type),
|
||||
_ID(_nextShaderID++)
|
||||
{
|
||||
}
|
||||
|
||||
Shader::Shader(Type type, const Pointer& vertex, const Pointer& pixel):
|
||||
_type(type)
|
||||
Shader::Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel):
|
||||
_type(type),
|
||||
_ID(_nextShaderID++)
|
||||
{
|
||||
_shaders.resize(2);
|
||||
_shaders[VERTEX] = vertex;
|
||||
_shaders[PIXEL] = pixel;
|
||||
}
|
||||
|
||||
Shader::Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel) :
|
||||
_type(type) {
|
||||
_shaders.resize(3);
|
||||
_shaders[VERTEX] = vertex;
|
||||
_shaders[GEOMETRY] = geometry;
|
||||
_shaders[PIXEL] = pixel;
|
||||
if (geometry) {
|
||||
_shaders.resize(3);
|
||||
_shaders[VERTEX] = vertex;
|
||||
_shaders[GEOMETRY] = geometry;
|
||||
_shaders[PIXEL] = pixel;
|
||||
} else {
|
||||
_shaders.resize(2);
|
||||
_shaders[VERTEX] = vertex;
|
||||
_shaders[PIXEL] = pixel;
|
||||
}
|
||||
}
|
||||
|
||||
Shader::~Shader()
|
||||
{
|
||||
}
|
||||
|
||||
Shader::Pointer Shader::createOrReuseDomainShader(Type type, const Source& source) {
|
||||
auto found = _domainShaderMaps[type].find(source);
|
||||
if (found != _domainShaderMaps[type].end()) {
|
||||
auto sharedShader = (*found).second.lock();
|
||||
if (sharedShader) {
|
||||
return sharedShader;
|
||||
}
|
||||
}
|
||||
auto shader = Pointer(new Shader(type, source));
|
||||
_domainShaderMaps[type].emplace(source, std::weak_ptr<Shader>(shader));
|
||||
return shader;
|
||||
}
|
||||
|
||||
Shader::Pointer Shader::createVertex(const Source& source) {
|
||||
return Pointer(new Shader(VERTEX, source));
|
||||
return createOrReuseDomainShader(VERTEX, source);
|
||||
}
|
||||
|
||||
Shader::Pointer Shader::createPixel(const Source& source) {
|
||||
return Pointer(new Shader(PIXEL, source));
|
||||
return createOrReuseDomainShader(PIXEL, source);
|
||||
}
|
||||
|
||||
Shader::Pointer Shader::createGeometry(const Source& source) {
|
||||
return Pointer(new Shader(GEOMETRY, source));
|
||||
return createOrReuseDomainShader(GEOMETRY, source);
|
||||
}
|
||||
|
||||
Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& pixelShader) {
|
||||
if (vertexShader && vertexShader->getType() == VERTEX &&
|
||||
pixelShader && pixelShader->getType() == PIXEL) {
|
||||
return Pointer(new Shader(PROGRAM, vertexShader, pixelShader));
|
||||
ShaderPointer Shader::createOrReuseProgramShader(Type type, const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader) {
|
||||
ProgramMapKey key(0);
|
||||
|
||||
if (vertexShader && vertexShader->getType() == VERTEX) {
|
||||
key.x = vertexShader->getID();
|
||||
} else {
|
||||
// Shader is not valid, exit
|
||||
return Pointer();
|
||||
}
|
||||
return Pointer();
|
||||
|
||||
if (pixelShader && pixelShader->getType() == PIXEL) {
|
||||
key.y = pixelShader->getID();
|
||||
} else {
|
||||
// Shader is not valid, exit
|
||||
return Pointer();
|
||||
}
|
||||
|
||||
if (geometryShader) {
|
||||
if (geometryShader->getType() == GEOMETRY) {
|
||||
key.z = geometryShader->getID();
|
||||
} else {
|
||||
// Shader is not valid, exit
|
||||
return Pointer();
|
||||
}
|
||||
}
|
||||
|
||||
// program key is defined, now try to reuse
|
||||
auto found = _programMap.find(key);
|
||||
if (found != _programMap.end()) {
|
||||
auto sharedShader = (*found).second.lock();
|
||||
if (sharedShader) {
|
||||
return sharedShader;
|
||||
}
|
||||
}
|
||||
|
||||
// Program is a new one, let's create it
|
||||
auto program = Pointer(new Shader(type, vertexShader, geometryShader, pixelShader));
|
||||
_programMap.emplace(key, std::weak_ptr<Shader>(program));
|
||||
return program;
|
||||
}
|
||||
|
||||
|
||||
Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& pixelShader) {
|
||||
return createOrReuseProgramShader(PROGRAM, vertexShader, nullptr, pixelShader);
|
||||
}
|
||||
|
||||
Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader) {
|
||||
if (vertexShader && vertexShader->getType() == VERTEX &&
|
||||
geometryShader && geometryShader->getType() == GEOMETRY &&
|
||||
pixelShader && pixelShader->getType() == PIXEL) {
|
||||
return Pointer(new Shader(PROGRAM, vertexShader, geometryShader, pixelShader));
|
||||
}
|
||||
return Pointer();
|
||||
return createOrReuseProgramShader(PROGRAM, vertexShader, geometryShader, pixelShader);
|
||||
}
|
||||
|
||||
void Shader::defineSlots(const SlotSet& uniforms, const SlotSet& uniformBuffers, const SlotSet& resourceBuffers, const SlotSet& textures, const SlotSet& samplers, const SlotSet& inputs, const SlotSet& outputs) {
|
||||
|
@ -82,9 +134,21 @@ void Shader::defineSlots(const SlotSet& uniforms, const SlotSet& uniformBuffers,
|
|||
_outputs = outputs;
|
||||
}
|
||||
|
||||
bool Shader::makeProgram(Shader& shader, const Shader::BindingSet& bindings) {
|
||||
bool Shader::makeProgram(Shader& shader, const Shader::BindingSet& bindings, const CompilationHandler& handler) {
|
||||
if (shader.isProgram()) {
|
||||
return Context::makeProgram(shader, bindings);
|
||||
return Context::makeProgram(shader, bindings, handler);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Shader::setCompilationLogs(const CompilationLogs& logs) const {
|
||||
_compilationLogs.clear();
|
||||
for (const auto& log : logs) {
|
||||
_compilationLogs.emplace_back(CompilationLog(log));
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::incrementCompilationAttempt() const {
|
||||
_numCompilationAttempts++;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,13 +15,16 @@
|
|||
#include <string>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <QUrl>
|
||||
|
||||
namespace gpu {
|
||||
|
||||
class Shader {
|
||||
public:
|
||||
// unique identifier of a shader
|
||||
using ID = uint32_t;
|
||||
|
||||
typedef std::shared_ptr< Shader > Pointer;
|
||||
typedef std::vector< Pointer > Shaders;
|
||||
|
@ -39,11 +42,29 @@ public:
|
|||
|
||||
virtual const std::string& getCode() const { return _code; }
|
||||
|
||||
class Less {
|
||||
public:
|
||||
bool operator() (const Source& x, const Source& y) const { if (x._lang == y._lang) { return x._code < y._code; } else { return (x._lang < y._lang); } }
|
||||
};
|
||||
|
||||
protected:
|
||||
std::string _code;
|
||||
Language _lang = GLSL;
|
||||
};
|
||||
|
||||
struct CompilationLog {
|
||||
std::string message;
|
||||
std::vector<char> binary;
|
||||
bool compiled{ false };
|
||||
|
||||
CompilationLog() {}
|
||||
CompilationLog(const CompilationLog& src) :
|
||||
message(src.message),
|
||||
binary(src.binary),
|
||||
compiled(src.compiled) {}
|
||||
};
|
||||
using CompilationLogs = std::vector<CompilationLog>;
|
||||
|
||||
static const int32 INVALID_LOCATION = -1;
|
||||
|
||||
class Slot {
|
||||
|
@ -121,13 +142,12 @@ public:
|
|||
|
||||
~Shader();
|
||||
|
||||
ID getID() const { return _ID; }
|
||||
|
||||
Type getType() const { return _type; }
|
||||
bool isProgram() const { return getType() > NUM_DOMAINS; }
|
||||
bool isDomain() const { return getType() < NUM_DOMAINS; }
|
||||
|
||||
void setCompilationHasFailed(bool compilationHasFailed) { _compilationHasFailed = compilationHasFailed; }
|
||||
bool compilationHasFailed() const { return _compilationHasFailed; }
|
||||
|
||||
const Source& getSource() const { return _source; }
|
||||
|
||||
const Shaders& getShaders() const { return _shaders; }
|
||||
|
@ -155,6 +175,15 @@ public:
|
|||
const SlotSet& inputs,
|
||||
const SlotSet& outputs);
|
||||
|
||||
// Compilation Handler can be passed while compiling a shader (in the makeProgram call) to be able to give the hand to
|
||||
// the caller thread if the comilation fails and to prvide a different version of the source for it
|
||||
// @param0 the Shader object that just failed to compile
|
||||
// @param1 the original source code as submited to the compiler
|
||||
// @param2 the compilation log containing the error message
|
||||
// @param3 a new string ready to be filled with the new version of the source that could be proposed from the handler functor
|
||||
// @return boolean true if the backend should keep trying to compile the shader with the new source returned or false to stop and fail that shader compilation
|
||||
using CompilationHandler = std::function<bool (const Shader&, const std::string&, CompilationLog&, std::string&)>;
|
||||
|
||||
// makeProgram(...) make a program shader ready to be used in a Batch.
|
||||
// It compiles the sub shaders, link them and defines the Slots and their bindings.
|
||||
// If the shader passed is not a program, nothing happens.
|
||||
|
@ -168,18 +197,29 @@ public:
|
|||
// on a gl Context and the driver to compile the glsl shader.
|
||||
// Hoppefully in a few years the shader compilation will be completely abstracted in a separate shader compiler library
|
||||
// independant of the graphics api in use underneath (looking at you opengl & vulkan).
|
||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet());
|
||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet(), const CompilationHandler& handler = nullptr);
|
||||
|
||||
// Check the compilation state
|
||||
bool compilationHasFailed() const { return _compilationHasFailed; }
|
||||
const CompilationLogs& getCompilationLogs() const { return _compilationLogs; }
|
||||
uint32_t getNumCompilationAttempts() const { return _numCompilationAttempts; }
|
||||
|
||||
// Set COmpilation logs can only be called by the Backend layers
|
||||
void setCompilationHasFailed(bool compilationHasFailed) { _compilationHasFailed = compilationHasFailed; }
|
||||
void setCompilationLogs(const CompilationLogs& logs) const;
|
||||
void incrementCompilationAttempt() const;
|
||||
|
||||
|
||||
const GPUObjectPointer gpuObject {};
|
||||
|
||||
|
||||
protected:
|
||||
Shader(Type type, const Source& source);
|
||||
Shader(Type type, const Pointer& vertex, const Pointer& pixel);
|
||||
Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel);
|
||||
|
||||
Shader(const Shader& shader); // deep copy of the sysmem shader
|
||||
Shader& operator=(const Shader& shader); // deep copy of the sysmem texture
|
||||
|
||||
|
||||
// Source contains the actual source code or nothing if the shader is a program
|
||||
Source _source;
|
||||
|
||||
|
@ -198,8 +238,49 @@ protected:
|
|||
// The type of the shader, the master key
|
||||
Type _type;
|
||||
|
||||
// The unique identifier of a shader in the GPU lib
|
||||
uint32_t _ID{ 0 };
|
||||
|
||||
// Number of attempts to compile the shader
|
||||
mutable uint32_t _numCompilationAttempts{ 0 };
|
||||
// Compilation logs (one for each versions generated)
|
||||
mutable CompilationLogs _compilationLogs;
|
||||
|
||||
// Whether or not the shader compilation failed
|
||||
bool _compilationHasFailed { false };
|
||||
|
||||
|
||||
// Global maps of the shaders
|
||||
// Unique shader ID
|
||||
static std::atomic<ID> _nextShaderID;
|
||||
|
||||
using ShaderMap = std::map<Source, std::weak_ptr<Shader>, Source::Less>;
|
||||
using DomainShaderMaps = std::array<ShaderMap, NUM_DOMAINS>;
|
||||
static DomainShaderMaps _domainShaderMaps;
|
||||
|
||||
static ShaderPointer createOrReuseDomainShader(Type type, const Source& source);
|
||||
|
||||
using ProgramMapKey = glm::uvec3; // The IDs of the shaders in a program make its key
|
||||
class ProgramKeyLess {
|
||||
public:
|
||||
bool operator() (const ProgramMapKey& l, const ProgramMapKey& r) const {
|
||||
if (l.x == r.x) {
|
||||
if (l.y == r.y) {
|
||||
return (l.z < r.z);
|
||||
}
|
||||
else {
|
||||
return (l.y < r.y);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return (l.x < r.x);
|
||||
}
|
||||
}
|
||||
};
|
||||
using ProgramMap = std::map<ProgramMapKey, std::weak_ptr<Shader>, ProgramKeyLess>;
|
||||
static ProgramMap _programMap;
|
||||
|
||||
static ShaderPointer createOrReuseProgramShader(Type type, const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader);
|
||||
};
|
||||
|
||||
typedef Shader::Pointer ShaderPointer;
|
||||
|
|
|
@ -28,7 +28,7 @@ class Backend : public gpu::Backend {
|
|||
friend class gpu::Context;
|
||||
static void init() {}
|
||||
static gpu::Backend* createBackend() { return new Backend(); }
|
||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings) { return true; }
|
||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler) { return true; }
|
||||
|
||||
protected:
|
||||
explicit Backend(bool syncCache) : Parent() { }
|
||||
|
|
|
@ -98,6 +98,7 @@ void DomainHandler::softReset() {
|
|||
clearSettings();
|
||||
|
||||
_connectionDenialsSinceKeypairRegen = 0;
|
||||
_checkInPacketsSinceLastReply = 0;
|
||||
|
||||
// cancel the failure timeout for any pending requests for settings
|
||||
QMetaObject::invokeMethod(&_settingsTimer, "stop");
|
||||
|
@ -382,6 +383,9 @@ void DomainHandler::processDomainServerConnectionDeniedPacket(QSharedPointer<Rec
|
|||
// we're hearing from this domain-server, don't need to refresh API info
|
||||
_apiRefreshTimer.stop();
|
||||
|
||||
// this counts as a reply from the DS after a check in or connect packet, so reset that counter now
|
||||
_checkInPacketsSinceLastReply = 0;
|
||||
|
||||
// Read deny reason from packet
|
||||
uint8_t reasonCodeWire;
|
||||
|
||||
|
@ -426,3 +430,14 @@ void DomainHandler::processDomainServerConnectionDeniedPacket(QSharedPointer<Rec
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DomainHandler::sentCheckInPacket() {
|
||||
++_checkInPacketsSinceLastReply;
|
||||
|
||||
if (_checkInPacketsSinceLastReply >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) {
|
||||
// we haven't heard back from DS in MAX_SILENT_DOMAIN_SERVER_CHECK_INS
|
||||
// so emit our signal that says that
|
||||
qCDebug(networking) << "Limit of silent domain checkins reached";
|
||||
emit limitOfSilentDomainCheckInsReached();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,8 @@ const unsigned short DEFAULT_DOMAIN_SERVER_DTLS_PORT = 40103;
|
|||
const quint16 DOMAIN_SERVER_HTTP_PORT = 40100;
|
||||
const quint16 DOMAIN_SERVER_HTTPS_PORT = 40101;
|
||||
|
||||
const int MAX_SILENT_DOMAIN_SERVER_CHECK_INS = 5;
|
||||
|
||||
class DomainHandler : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
@ -84,6 +86,10 @@ public:
|
|||
|
||||
void softReset();
|
||||
|
||||
int getCheckInPacketsSinceLastReply() const { return _checkInPacketsSinceLastReply; }
|
||||
void sentCheckInPacket();
|
||||
void domainListReceived() { _checkInPacketsSinceLastReply = 0; }
|
||||
|
||||
/**jsdoc
|
||||
* <p>The reasons that you may be refused connection to a domain are defined by numeric values:</p>
|
||||
* <table>
|
||||
|
@ -165,6 +171,8 @@ signals:
|
|||
|
||||
void domainConnectionRefused(QString reasonMessage, int reason, const QString& extraInfo);
|
||||
|
||||
void limitOfSilentDomainCheckInsReached();
|
||||
|
||||
private:
|
||||
bool reasonSuggestsLogin(ConnectionRefusedReason reasonCode);
|
||||
void sendDisconnectPacket();
|
||||
|
@ -187,6 +195,7 @@ private:
|
|||
QSet<QString> _domainConnectionRefusals;
|
||||
bool _hasCheckedForAccessToken { false };
|
||||
int _connectionDenialsSinceKeypairRegen { 0 };
|
||||
int _checkInPacketsSinceLastReply { 0 };
|
||||
|
||||
QTimer _apiRefreshTimer;
|
||||
};
|
||||
|
|
|
@ -44,7 +44,6 @@ NodeList::NodeList(char newOwnerType, int socketListenPort, int dtlsListenPort)
|
|||
_ownerType(newOwnerType),
|
||||
_nodeTypesOfInterest(),
|
||||
_domainHandler(this),
|
||||
_numNoReplyDomainCheckIns(0),
|
||||
_assignmentServerSocket(),
|
||||
_keepAlivePingTimer(this)
|
||||
{
|
||||
|
@ -75,7 +74,7 @@ NodeList::NodeList(char newOwnerType, int socketListenPort, int dtlsListenPort)
|
|||
connect(this, &LimitedNodeList::publicSockAddrChanged, this, &NodeList::sendDomainServerCheckIn);
|
||||
|
||||
// clear our NodeList when the domain changes
|
||||
connect(&_domainHandler, &DomainHandler::disconnectedFromDomain, this, &NodeList::reset);
|
||||
connect(&_domainHandler, SIGNAL(disconnectedFromDomain()), this, SLOT(resetFromDomainHandler()));
|
||||
|
||||
// send an ICE heartbeat as soon as we get ice server information
|
||||
connect(&_domainHandler, &DomainHandler::iceSocketAndIDReceived, this, &NodeList::handleICEConnectionToDomainServer);
|
||||
|
@ -92,10 +91,10 @@ NodeList::NodeList(char newOwnerType, int socketListenPort, int dtlsListenPort)
|
|||
connect(accountManager.data(), &AccountManager::newKeypair, this, &NodeList::sendDomainServerCheckIn);
|
||||
|
||||
// clear out NodeList when login is finished
|
||||
connect(accountManager.data(), &AccountManager::loginComplete , this, &NodeList::reset);
|
||||
connect(accountManager.data(), SIGNAL(loginComplete()) , this, SLOT(reset()));
|
||||
|
||||
// clear our NodeList when logout is requested
|
||||
connect(accountManager.data(), &AccountManager::logoutComplete , this, &NodeList::reset);
|
||||
connect(accountManager.data(), SIGNAL(logoutComplete()) , this, SLOT(reset()));
|
||||
|
||||
// anytime we get a new node we will want to attempt to punch to it
|
||||
connect(this, &LimitedNodeList::nodeAdded, this, &NodeList::startNodeHolePunch);
|
||||
|
@ -231,16 +230,14 @@ void NodeList::processICEPingPacket(QSharedPointer<ReceivedMessage> message) {
|
|||
sendPacket(std::move(replyPacket), message->getSenderSockAddr());
|
||||
}
|
||||
|
||||
void NodeList::reset() {
|
||||
void NodeList::reset(bool skipDomainHandlerReset) {
|
||||
if (thread() != QThread::currentThread()) {
|
||||
QMetaObject::invokeMethod(this, "reset");
|
||||
QMetaObject::invokeMethod(this, "reset", Q_ARG(bool, skipDomainHandlerReset));
|
||||
return;
|
||||
}
|
||||
|
||||
LimitedNodeList::reset();
|
||||
|
||||
_numNoReplyDomainCheckIns = 0;
|
||||
|
||||
// lock and clear our set of ignored IDs
|
||||
_ignoredSetLock.lockForWrite();
|
||||
_ignoredNodeIDs.clear();
|
||||
|
@ -255,7 +252,7 @@ void NodeList::reset() {
|
|||
_avatarGainMap.clear();
|
||||
_avatarGainMapLock.unlock();
|
||||
|
||||
if (sender() != &_domainHandler) {
|
||||
if (!skipDomainHandlerReset) {
|
||||
// clear the domain connection information, unless they're the ones that asked us to reset
|
||||
_domainHandler.softReset();
|
||||
}
|
||||
|
@ -410,15 +407,8 @@ void NodeList::sendDomainServerCheckIn() {
|
|||
|
||||
sendPacket(std::move(domainPacket), _domainHandler.getSockAddr());
|
||||
|
||||
if (_numNoReplyDomainCheckIns >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) {
|
||||
// we haven't heard back from DS in MAX_SILENT_DOMAIN_SERVER_CHECK_INS
|
||||
// so emit our signal that says that
|
||||
qCDebug(networking) << "Limit of silent domain checkins reached";
|
||||
emit limitOfSilentDomainCheckInsReached();
|
||||
}
|
||||
|
||||
// increment the count of un-replied check-ins
|
||||
_numNoReplyDomainCheckIns++;
|
||||
// let the domain handler know we sent another check in or connect packet
|
||||
_domainHandler.sentCheckInPacket();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -585,7 +575,7 @@ void NodeList::processDomainServerList(QSharedPointer<ReceivedMessage> message)
|
|||
}
|
||||
|
||||
// this is a packet from the domain server, reset the count of un-replied check-ins
|
||||
_numNoReplyDomainCheckIns = 0;
|
||||
_domainHandler.domainListReceived();
|
||||
|
||||
// emit our signal so listeners know we just heard from the DS
|
||||
emit receivedDomainServerList();
|
||||
|
|
|
@ -38,8 +38,6 @@
|
|||
|
||||
const quint64 DOMAIN_SERVER_CHECK_IN_MSECS = 1 * 1000;
|
||||
|
||||
const int MAX_SILENT_DOMAIN_SERVER_CHECK_INS = 5;
|
||||
|
||||
using PacketOrPacketList = std::pair<std::unique_ptr<NLPacket>, std::unique_ptr<NLPacketList>>;
|
||||
using NodePacketOrPacketListPair = std::pair<SharedNodePointer, PacketOrPacketList>;
|
||||
|
||||
|
@ -62,7 +60,6 @@ public:
|
|||
Q_INVOKABLE qint64 sendStats(QJsonObject statsObject, HifiSockAddr destination);
|
||||
Q_INVOKABLE qint64 sendStatsToDomainServer(QJsonObject statsObject);
|
||||
|
||||
int getNumNoReplyDomainCheckIns() const { return _numNoReplyDomainCheckIns; }
|
||||
DomainHandler& getDomainHandler() { return _domainHandler; }
|
||||
|
||||
const NodeSet& getNodeInterestSet() const { return _nodeTypesOfInterest; }
|
||||
|
@ -96,7 +93,9 @@ public:
|
|||
void removeFromIgnoreMuteSets(const QUuid& nodeID);
|
||||
|
||||
public slots:
|
||||
void reset();
|
||||
void reset(bool skipDomainHandlerReset = false);
|
||||
void resetFromDomainHandler() { reset(true); }
|
||||
|
||||
void sendDomainServerCheckIn();
|
||||
void handleDSPathQuery(const QString& newPath);
|
||||
|
||||
|
@ -119,7 +118,6 @@ public slots:
|
|||
#endif
|
||||
|
||||
signals:
|
||||
void limitOfSilentDomainCheckInsReached();
|
||||
void receivedDomainServerList();
|
||||
void ignoredNode(const QUuid& nodeID, bool enabled);
|
||||
void ignoreRadiusEnabledChanged(bool isIgnored);
|
||||
|
@ -161,7 +159,6 @@ private:
|
|||
std::atomic<NodeType_t> _ownerType;
|
||||
NodeSet _nodeTypesOfInterest;
|
||||
DomainHandler _domainHandler;
|
||||
int _numNoReplyDomainCheckIns;
|
||||
HifiSockAddr _assignmentServerSocket;
|
||||
bool _isShuttingDown { false };
|
||||
QTimer _keepAlivePingTimer;
|
||||
|
|
|
@ -203,6 +203,12 @@ vec3 evalGlobalLightingAlphaBlended(mat4 invViewMat, float shadowAttenuation, fl
|
|||
|
||||
return color;
|
||||
}
|
||||
<@endfunc@>
|
||||
|
||||
<@func declareEvalGlobalLightingAlphaBlendedWithHaze()@>
|
||||
|
||||
<$declareLightingAmbient(1, 1, 1)$>
|
||||
<$declareLightingDirectional()$>
|
||||
|
||||
vec3 evalGlobalLightingAlphaBlendedWithHaze(
|
||||
mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal,
|
||||
|
|
|
@ -46,7 +46,7 @@ vec3 evalAmbientSpecularIrradiance(LightAmbient ambient, SurfaceData surface) {
|
|||
float levels = getLightAmbientMapNumMips(ambient);
|
||||
float m = 12.0 / (1.0+11.0*surface.roughness);
|
||||
float lod = levels - m;
|
||||
lod = max(lod, 0);
|
||||
lod = max(lod, 0.0);
|
||||
specularLight = evalSkyboxLight(lightDir, lod).xyz;
|
||||
}
|
||||
<@endif@>
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include "model_lightmap_fade_vert.h"
|
||||
#include "model_lightmap_normal_map_fade_vert.h"
|
||||
#include "model_translucent_vert.h"
|
||||
#include "model_translucent_fade_vert.h"
|
||||
#include "model_translucent_normal_map_vert.h"
|
||||
#include "skin_model_fade_vert.h"
|
||||
#include "skin_model_normal_map_fade_vert.h"
|
||||
|
||||
|
@ -73,12 +73,14 @@
|
|||
#include "model_lightmap_specular_map_frag.h"
|
||||
#include "model_translucent_frag.h"
|
||||
#include "model_translucent_unlit_frag.h"
|
||||
#include "model_translucent_normal_map_frag.h"
|
||||
|
||||
#include "model_lightmap_fade_frag.h"
|
||||
#include "model_lightmap_normal_map_fade_frag.h"
|
||||
#include "model_lightmap_normal_specular_map_fade_frag.h"
|
||||
#include "model_lightmap_specular_map_fade_frag.h"
|
||||
#include "model_translucent_fade_frag.h"
|
||||
#include "model_translucent_normal_map_fade_frag.h"
|
||||
#include "model_translucent_unlit_fade_frag.h"
|
||||
|
||||
#include "overlay3D_vert.h"
|
||||
|
@ -191,7 +193,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
|
|||
auto modelLightmapVertex = gpu::Shader::createVertex(std::string(model_lightmap_vert));
|
||||
auto modelLightmapNormalMapVertex = gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert));
|
||||
auto modelTranslucentVertex = gpu::Shader::createVertex(std::string(model_translucent_vert));
|
||||
auto modelTranslucentFadeVertex = gpu::Shader::createVertex(std::string(model_translucent_fade_vert));
|
||||
auto modelTranslucentNormalMapVertex = gpu::Shader::createVertex(std::string(model_translucent_normal_map_vert));
|
||||
auto modelShadowVertex = gpu::Shader::createVertex(std::string(model_shadow_vert));
|
||||
auto skinModelVertex = gpu::Shader::createVertex(std::string(skin_model_vert));
|
||||
auto skinModelNormalMapVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_vert));
|
||||
|
@ -220,6 +222,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
|
|||
auto modelSpecularMapPixel = gpu::Shader::createPixel(std::string(model_specular_map_frag));
|
||||
auto modelNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_frag));
|
||||
auto modelTranslucentPixel = gpu::Shader::createPixel(std::string(model_translucent_frag));
|
||||
auto modelTranslucentNormalMapPixel = gpu::Shader::createPixel(std::string(model_translucent_normal_map_frag));
|
||||
auto modelTranslucentUnlitPixel = gpu::Shader::createPixel(std::string(model_translucent_unlit_frag));
|
||||
auto modelShadowPixel = gpu::Shader::createPixel(std::string(model_shadow_frag));
|
||||
auto modelLightmapPixel = gpu::Shader::createPixel(std::string(model_lightmap_frag));
|
||||
|
@ -238,6 +241,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
|
|||
auto modelNormalSpecularMapFadePixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_fade_frag));
|
||||
auto modelShadowFadePixel = gpu::Shader::createPixel(std::string(model_shadow_fade_frag));
|
||||
auto modelTranslucentFadePixel = gpu::Shader::createPixel(std::string(model_translucent_fade_frag));
|
||||
auto modelTranslucentNormalMapFadePixel = gpu::Shader::createPixel(std::string(model_translucent_normal_map_fade_frag));
|
||||
auto modelTranslucentUnlitFadePixel = gpu::Shader::createPixel(std::string(model_translucent_unlit_fade_frag));
|
||||
auto simpleFadePixel = gpu::Shader::createPixel(std::string(simple_textured_fade_frag));
|
||||
auto simpleUnlitFadePixel = gpu::Shader::createPixel(std::string(simple_textured_unlit_fade_frag));
|
||||
|
@ -307,13 +311,13 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
|
|||
simpleVertex, simpleTranslucentUnlitPixel, nullptr, nullptr);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withTranslucent().withTangents(),
|
||||
modelTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
|
||||
modelTranslucentNormalMapVertex, modelTranslucentNormalMapPixel, nullptr, nullptr);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withTranslucent().withSpecular(),
|
||||
modelTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withTranslucent().withTangents().withSpecular(),
|
||||
modelTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
|
||||
modelTranslucentNormalMapVertex, modelTranslucentNormalMapPixel, nullptr, nullptr);
|
||||
addPipeline(
|
||||
// FIXME: Ignore lightmap for translucents meshpart
|
||||
Key::Builder().withMaterial().withTranslucent().withLightmap(),
|
||||
|
@ -321,7 +325,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
|
|||
// Same thing but with Fade on
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withTranslucent().withFade(),
|
||||
modelTranslucentFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
|
||||
modelTranslucentVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
|
||||
addPipeline(
|
||||
Key::Builder().withTranslucent().withFade(),
|
||||
simpleFadeVertex, simpleTranslucentFadePixel, batchSetter, itemSetter);
|
||||
|
@ -333,13 +337,13 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
|
|||
simpleFadeVertex, simpleTranslucentUnlitFadePixel, batchSetter, itemSetter);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withTranslucent().withTangents().withFade(),
|
||||
modelNormalMapFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
|
||||
modelTranslucentNormalMapVertex, modelTranslucentNormalMapFadePixel, batchSetter, itemSetter);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withTranslucent().withSpecular().withFade(),
|
||||
modelFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withTranslucent().withTangents().withSpecular().withFade(),
|
||||
modelNormalMapFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
|
||||
modelTranslucentNormalMapVertex, modelTranslucentNormalMapFadePixel, batchSetter, itemSetter);
|
||||
addPipeline(
|
||||
// FIXME: Ignore lightmap for translucents meshpart
|
||||
Key::Builder().withMaterial().withTranslucent().withLightmap().withFade(),
|
||||
|
@ -405,26 +409,26 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
|
|||
skinModelTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents(),
|
||||
skinModelNormalMapTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
|
||||
skinModelNormalMapTranslucentVertex, modelTranslucentNormalMapPixel, nullptr, nullptr);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withTranslucent().withSpecular(),
|
||||
skinModelTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withSpecular(),
|
||||
skinModelNormalMapTranslucentVertex, modelTranslucentPixel, nullptr, nullptr);
|
||||
skinModelNormalMapTranslucentVertex, modelTranslucentNormalMapPixel, nullptr, nullptr);
|
||||
// Same thing but with Fade on
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withTranslucent().withFade(),
|
||||
skinModelFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withFade(),
|
||||
skinModelNormalMapFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
|
||||
skinModelNormalMapFadeVertex, modelTranslucentNormalMapFadePixel, batchSetter, itemSetter);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withTranslucent().withSpecular().withFade(),
|
||||
skinModelFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withSpecular().withFade(),
|
||||
skinModelNormalMapFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
|
||||
skinModelNormalMapFadeVertex, modelTranslucentNormalMapFadePixel, batchSetter, itemSetter);
|
||||
|
||||
// Depth-only
|
||||
addPipeline(
|
||||
|
|
|
@ -47,7 +47,7 @@ void main(void) {
|
|||
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
|
||||
|
||||
vec3 viewNormal;
|
||||
<$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, viewNormal)$>
|
||||
<$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, viewNormal)$>
|
||||
|
||||
float scattering = getMaterialScattering(mat);
|
||||
<$evalMaterialScattering(scatteringTex, scattering, matKey, scattering)$>;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
<@include DeferredGlobalLight.slh@>
|
||||
|
||||
<$declareEvalGlobalLightingAlphaBlended()$>
|
||||
<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
|
||||
|
||||
<@include LightLocal.slh@>
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
<@include DeferredGlobalLight.slh@>
|
||||
|
||||
<$declareEvalGlobalLightingAlphaBlended()$>
|
||||
<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
|
||||
|
||||
<@include LightLocal.slh@>
|
||||
|
||||
|
|
91
libraries/render-utils/src/model_translucent_normal_map.slf
Normal file
91
libraries/render-utils/src/model_translucent_normal_map.slf
Normal file
|
@ -0,0 +1,91 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// model_translucent_normal_map.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Olivier Prat on 23/01/2018.
|
||||
// Copyright 2018 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 graphics/Material.slh@>
|
||||
|
||||
<@include DeferredGlobalLight.slh@>
|
||||
|
||||
<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
|
||||
|
||||
<@include LightLocal.slh@>
|
||||
|
||||
<@include gpu/Transform.slh@>
|
||||
<$declareStandardCameraTransform()$>
|
||||
|
||||
<@include MaterialTextures.slh@>
|
||||
<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$>
|
||||
|
||||
in vec2 _texCoord0;
|
||||
in vec2 _texCoord1;
|
||||
in vec4 _position;
|
||||
in vec4 _worldPosition;
|
||||
in vec3 _normal;
|
||||
in vec3 _tangent;
|
||||
in vec3 _color;
|
||||
in float _alpha;
|
||||
|
||||
out vec4 _fragColor;
|
||||
|
||||
void main(void) {
|
||||
Material mat = getMaterial();
|
||||
int matKey = getMaterialKey(mat);
|
||||
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, normalTex, _SCRIBE_NULL, emissiveTex)$>
|
||||
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$>
|
||||
|
||||
float opacity = getMaterialOpacity(mat) * _alpha;
|
||||
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
|
||||
|
||||
vec3 albedo = getMaterialAlbedo(mat);
|
||||
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
|
||||
albedo *= _color;
|
||||
|
||||
float roughness = getMaterialRoughness(mat);
|
||||
<$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>;
|
||||
|
||||
float metallic = getMaterialMetallic(mat);
|
||||
vec3 fresnel = getFresnelF0(metallic, albedo);
|
||||
|
||||
vec3 emissive = getMaterialEmissive(mat);
|
||||
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
|
||||
|
||||
vec3 fragPosition = _position.xyz;
|
||||
vec3 fragNormal;
|
||||
<$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
|
||||
|
||||
TransformCamera cam = getTransformCamera();
|
||||
vec3 fragEyeVector = vec3(cam._viewInverse * vec4(-fragPosition, 0.0));
|
||||
vec3 fragEyeDir = normalize(fragEyeVector);
|
||||
SurfaceData surface = initSurfaceData(roughness, fragNormal, fragEyeDir);
|
||||
|
||||
vec4 localLighting = vec4(0.0);
|
||||
|
||||
<$fetchClusterInfo(_worldPosition)$>;
|
||||
if (hasLocalLights(numLights, clusterPos, dims)) {
|
||||
localLighting = evalLocalLighting(cluster, numLights, _worldPosition.xyz, surface,
|
||||
metallic, fresnel, albedo, 0.0,
|
||||
vec4(0), vec4(0), opacity);
|
||||
}
|
||||
|
||||
_fragColor = vec4(evalGlobalLightingAlphaBlendedWithHaze(
|
||||
cam._viewInverse,
|
||||
1.0,
|
||||
occlusionTex,
|
||||
fragPosition,
|
||||
albedo,
|
||||
fresnel,
|
||||
metallic,
|
||||
emissive,
|
||||
surface, opacity, localLighting.rgb),
|
||||
opacity);
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
// model_translucent_fade.slv
|
||||
// model_translucent_normal_map.slv
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Olivier Prat on 15/01/18.
|
||||
// Created by Olivier Prat on 23/01/18.
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
|
@ -25,6 +25,7 @@ out vec2 _texCoord1;
|
|||
out vec4 _position;
|
||||
out vec4 _worldPosition;
|
||||
out vec3 _normal;
|
||||
out vec3 _tangent;
|
||||
out vec3 _color;
|
||||
|
||||
void main(void) {
|
||||
|
@ -41,4 +42,5 @@ void main(void) {
|
|||
<$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$>
|
||||
<$transformModelToWorldPos(obj, inPosition, _worldPosition)$>
|
||||
<$transformModelToWorldDir(cam, obj, inNormal.xyz, _normal)$>
|
||||
<$transformModelToWorldDir(cam, obj, inTangent.xyz, _tangent)$>
|
||||
}
|
101
libraries/render-utils/src/model_translucent_normal_map_fade.slf
Normal file
101
libraries/render-utils/src/model_translucent_normal_map_fade.slf
Normal file
|
@ -0,0 +1,101 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// model_translucent_normal_map_fade.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Olivier Prat on 23/01/18.
|
||||
// Copyright 2018 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 graphics/Material.slh@>
|
||||
|
||||
<@include DeferredGlobalLight.slh@>
|
||||
|
||||
<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
|
||||
|
||||
<@include LightLocal.slh@>
|
||||
|
||||
<@include gpu/Transform.slh@>
|
||||
<$declareStandardCameraTransform()$>
|
||||
|
||||
<@include MaterialTextures.slh@>
|
||||
<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$>
|
||||
|
||||
<@include Fade.slh@>
|
||||
<$declareFadeFragment()$>
|
||||
|
||||
in vec2 _texCoord0;
|
||||
in vec2 _texCoord1;
|
||||
in vec4 _position;
|
||||
in vec3 _normal;
|
||||
in vec3 _tangent;
|
||||
in vec3 _color;
|
||||
in float _alpha;
|
||||
in vec4 _worldPosition;
|
||||
|
||||
out vec4 _fragColor;
|
||||
|
||||
void main(void) {
|
||||
vec3 fadeEmissive;
|
||||
FadeObjectParams fadeParams;
|
||||
|
||||
<$fetchFadeObjectParams(fadeParams)$>
|
||||
applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
|
||||
|
||||
Material mat = getMaterial();
|
||||
int matKey = getMaterialKey(mat);
|
||||
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, normalTex, _SCRIBE_NULL, emissiveTex)$>
|
||||
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$>
|
||||
|
||||
float opacity = getMaterialOpacity(mat) * _alpha;
|
||||
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
|
||||
|
||||
vec3 albedo = getMaterialAlbedo(mat);
|
||||
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
|
||||
albedo *= _color;
|
||||
|
||||
float roughness = getMaterialRoughness(mat);
|
||||
<$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>;
|
||||
|
||||
float metallic = getMaterialMetallic(mat);
|
||||
vec3 fresnel = getFresnelF0(metallic, albedo);
|
||||
|
||||
vec3 emissive = getMaterialEmissive(mat);
|
||||
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
|
||||
|
||||
vec3 fragPosition = _position.xyz;
|
||||
// Lighting is done in world space
|
||||
vec3 fragNormal;
|
||||
<$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
|
||||
|
||||
TransformCamera cam = getTransformCamera();
|
||||
vec3 fragEyeVector = vec3(cam._viewInverse * vec4(-fragPosition, 0.0));
|
||||
vec3 fragEyeDir = normalize(fragEyeVector);
|
||||
SurfaceData surface = initSurfaceData(roughness, fragNormal, fragEyeDir);
|
||||
|
||||
vec4 localLighting = vec4(0.0);
|
||||
|
||||
<$fetchClusterInfo(_worldPosition)$>;
|
||||
if (hasLocalLights(numLights, clusterPos, dims)) {
|
||||
localLighting = evalLocalLighting(cluster, numLights, _worldPosition.xyz, surface,
|
||||
metallic, fresnel, albedo, 0.0,
|
||||
vec4(0), vec4(0), opacity);
|
||||
}
|
||||
|
||||
_fragColor = vec4(evalGlobalLightingAlphaBlendedWithHaze(
|
||||
cam._viewInverse,
|
||||
1.0,
|
||||
occlusionTex,
|
||||
fragPosition,
|
||||
albedo,
|
||||
fresnel,
|
||||
metallic,
|
||||
emissive+fadeEmissive,
|
||||
surface, opacity, localLighting.rgb),
|
||||
opacity);
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
//
|
||||
|
||||
<@include DeferredGlobalLight.slh@>
|
||||
<$declareEvalGlobalLightingAlphaBlended()$>
|
||||
<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
|
||||
|
||||
<@include graphics/Material.slh@>
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
<@include DeferredBufferWrite.slh@>
|
||||
<@include DeferredGlobalLight.slh@>
|
||||
<$declareEvalGlobalLightingAlphaBlended()$>
|
||||
<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
|
||||
|
||||
<@include gpu/Transform.slh@>
|
||||
<$declareStandardCameraTransform()$>
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
<@include DeferredBufferWrite.slh@>
|
||||
<@include DeferredGlobalLight.slh@>
|
||||
<$declareEvalGlobalLightingAlphaBlended()$>
|
||||
<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
|
||||
|
||||
<@include gpu/Transform.slh@>
|
||||
<$declareStandardCameraTransform()$>
|
||||
|
|
|
@ -73,8 +73,9 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p
|
|||
|
||||
ShapeKey key{ filter._flags };
|
||||
|
||||
|
||||
// don't call makeProgram on shaders that are already made.
|
||||
if (program->getUniformBuffers().empty()) {
|
||||
if (program->getNumCompilationAttempts() < 1) {
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("lightingModelBuffer"), Slot::BUFFER::LIGHTING_MODEL));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Slot::BUFFER::SKINNING));
|
||||
|
|
|
@ -200,9 +200,10 @@ public:
|
|||
std::string fsSource = HMD_REPROJECTION_FRAG;
|
||||
GLuint vertexShader { 0 }, fragmentShader { 0 };
|
||||
std::string error;
|
||||
std::vector<char> binary;
|
||||
::gl::compileShader(GL_VERTEX_SHADER, vsSource, "", vertexShader, error);
|
||||
::gl::compileShader(GL_FRAGMENT_SHADER, fsSource, "", fragmentShader, error);
|
||||
_program = ::gl::compileProgram({ { vertexShader, fragmentShader } }, error);
|
||||
_program = ::gl::compileProgram({ { vertexShader, fragmentShader } }, error, binary);
|
||||
glDeleteShader(vertexShader);
|
||||
glDeleteShader(fragmentShader);
|
||||
qDebug() << "Rebuild proigram";
|
||||
|
|
|
@ -527,6 +527,80 @@
|
|||
//
|
||||
//***********************************************
|
||||
|
||||
var sendMoneyRecipient;
|
||||
var sendMoneyParticleEffectUpdateTimer;
|
||||
var particleEffectTimestamp;
|
||||
var sendMoneyParticleEffect;
|
||||
var SEND_MONEY_PARTICLE_TIMER_UPDATE = 250;
|
||||
var SEND_MONEY_PARTICLE_EMITTING_DURATION = 3000;
|
||||
var SEND_MONEY_PARTICLE_LIFETIME_SECONDS = 8;
|
||||
var SEND_MONEY_PARTICLE_PROPERTIES = {
|
||||
accelerationSpread: { x: 0, y: 0, z: 0 },
|
||||
alpha: 1,
|
||||
alphaFinish: 1,
|
||||
alphaSpread: 0,
|
||||
alphaStart: 1,
|
||||
azimuthFinish: 0,
|
||||
azimuthStart: -6,
|
||||
color: { red: 143, green: 5, blue: 255 },
|
||||
colorFinish: { red: 255, green: 0, blue: 204 },
|
||||
colorSpread: { red: 0, green: 0, blue: 0 },
|
||||
colorStart: { red: 0, green: 136, blue: 255 },
|
||||
emitAcceleration: { x: 0, y: 0, z: 0 }, // Immediately gets updated to be accurate
|
||||
emitDimensions: { x: 0, y: 0, z: 0 },
|
||||
emitOrientation: { x: 0, y: 0, z: 0 },
|
||||
emitRate: 4,
|
||||
emitSpeed: 2.1,
|
||||
emitterShouldTrail: true,
|
||||
isEmitting: 1,
|
||||
lifespan: SEND_MONEY_PARTICLE_LIFETIME_SECONDS + 1, // Immediately gets updated to be accurate
|
||||
lifetime: SEND_MONEY_PARTICLE_LIFETIME_SECONDS + 1,
|
||||
maxParticles: 20,
|
||||
name: 'hfc-particles',
|
||||
particleRadius: 0.2,
|
||||
polarFinish: 0,
|
||||
polarStart: 0,
|
||||
radiusFinish: 0.05,
|
||||
radiusSpread: 0,
|
||||
radiusStart: 0.2,
|
||||
speedSpread: 0,
|
||||
textures: "http://hifi-content.s3.amazonaws.com/alan/dev/Particles/Bokeh-Particle-HFC.png",
|
||||
type: 'ParticleEffect'
|
||||
};
|
||||
|
||||
function updateSendMoneyParticleEffect() {
|
||||
var timestampNow = Date.now();
|
||||
if ((timestampNow - particleEffectTimestamp) > (SEND_MONEY_PARTICLE_LIFETIME_SECONDS * 1000)) {
|
||||
deleteSendMoneyParticleEffect();
|
||||
return;
|
||||
} else if ((timestampNow - particleEffectTimestamp) > SEND_MONEY_PARTICLE_EMITTING_DURATION) {
|
||||
Entities.editEntity(sendMoneyParticleEffect, {
|
||||
isEmitting: 0
|
||||
});
|
||||
} else if (sendMoneyParticleEffect) {
|
||||
var recipientPosition = AvatarList.getAvatar(sendMoneyRecipient).position;
|
||||
var distance = Vec3.distance(recipientPosition, MyAvatar.position);
|
||||
var accel = Vec3.subtract(recipientPosition, MyAvatar.position);
|
||||
accel.y -= 3.0;
|
||||
var life = Math.sqrt(2 * distance / Vec3.length(accel));
|
||||
Entities.editEntity(sendMoneyParticleEffect, {
|
||||
emitAcceleration: accel,
|
||||
lifespan: life
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function deleteSendMoneyParticleEffect() {
|
||||
if (sendMoneyParticleEffectUpdateTimer) {
|
||||
Script.clearInterval(sendMoneyParticleEffectUpdateTimer);
|
||||
sendMoneyParticleEffectUpdateTimer = null;
|
||||
}
|
||||
if (sendMoneyParticleEffect) {
|
||||
sendMoneyParticleEffect = Entities.deleteEntity(sendMoneyParticleEffect);
|
||||
}
|
||||
sendMoneyRecipient = null;
|
||||
}
|
||||
|
||||
// Function Name: fromQml()
|
||||
//
|
||||
// Description:
|
||||
|
@ -534,6 +608,7 @@
|
|||
// in the format "{method, params}", like json-rpc. See also sendToQml().
|
||||
var isHmdPreviewDisabled = true;
|
||||
var MARKETPLACES_INJECT_SCRIPT_URL = Script.resolvePath("../html/js/marketplacesInject.js");
|
||||
|
||||
function fromQml(message) {
|
||||
switch (message.method) {
|
||||
case 'passphrasePopup_cancelClicked':
|
||||
|
@ -605,6 +680,19 @@
|
|||
}
|
||||
removeOverlays();
|
||||
break;
|
||||
case 'sendMoney_sendPublicly':
|
||||
deleteSendMoneyParticleEffect();
|
||||
sendMoneyRecipient = message.recipient;
|
||||
var amount = message.amount;
|
||||
var props = SEND_MONEY_PARTICLE_PROPERTIES;
|
||||
props.parentID = MyAvatar.sessionUUID;
|
||||
props.position = MyAvatar.position;
|
||||
props.position.y += 0.2;
|
||||
sendMoneyParticleEffect = Entities.addEntity(props, true);
|
||||
particleEffectTimestamp = Date.now();
|
||||
updateSendMoneyParticleEffect();
|
||||
sendMoneyParticleEffectUpdateTimer = Script.setInterval(updateSendMoneyParticleEffect, SEND_MONEY_PARTICLE_TIMER_UPDATE);
|
||||
break;
|
||||
default:
|
||||
print('Unrecognized message from QML:', JSON.stringify(message));
|
||||
}
|
||||
|
@ -706,6 +794,7 @@
|
|||
function shutdown() {
|
||||
button.clicked.disconnect(onButtonClicked);
|
||||
tablet.removeButton(button);
|
||||
deleteSendMoneyParticleEffect();
|
||||
if (tablet) {
|
||||
tablet.screenChanged.disconnect(onTabletScreenChanged);
|
||||
if (onWalletScreen) {
|
||||
|
|
|
@ -578,6 +578,7 @@ var selectionDisplay = null; // for gridTool.js to ignore
|
|||
case 'refreshConnections':
|
||||
case 'enable_ChooseRecipientNearbyMode':
|
||||
case 'disable_ChooseRecipientNearbyMode':
|
||||
case 'sendMoney_sendPublicly':
|
||||
// NOP
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -137,12 +137,13 @@ const std::string PIXEL_SHADER_DEFINES{ R"GLSL(
|
|||
|
||||
void testShaderBuild(const char* vs_src, const char * fs_src) {
|
||||
std::string error;
|
||||
std::vector<char> binary;
|
||||
GLuint vs, fs;
|
||||
if (!gl::compileShader(GL_VERTEX_SHADER, vs_src, VERTEX_SHADER_DEFINES, vs, error) ||
|
||||
!gl::compileShader(GL_FRAGMENT_SHADER, fs_src, PIXEL_SHADER_DEFINES, fs, error)) {
|
||||
throw std::runtime_error("Failed to compile shader");
|
||||
}
|
||||
auto pr = gl::compileProgram({ vs, fs }, error);
|
||||
auto pr = gl::compileProgram({ vs, fs }, error, binary);
|
||||
if (!pr) {
|
||||
throw std::runtime_error("Failed to link shader");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue