Merged with master

This commit is contained in:
Olivier Prat 2018-02-05 18:24:05 +01:00
commit 92279b5939
86 changed files with 1166 additions and 359 deletions

View file

@ -571,6 +571,7 @@ Rectangle {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
hoverEnabled: true;
}
RalewayBold {

View file

@ -45,6 +45,7 @@ Rectangle {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
hoverEnabled: true;
}
Rectangle {

View file

@ -44,6 +44,7 @@ Rectangle {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
hoverEnabled: true;
}
Item {

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View file

@ -119,6 +119,7 @@ Rectangle {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
hoverEnabled: true;
}
Image {

View file

@ -316,6 +316,7 @@ Item {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
hoverEnabled: true;
}
RalewayBold {

View file

@ -66,6 +66,7 @@ Item {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
hoverEnabled: true;
}
// This will cause a bug -- if you bring up passphrase selection in HUD mode while

View file

@ -34,6 +34,7 @@ Item {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
hoverEnabled: true;
}
Connections {

View file

@ -306,6 +306,7 @@ Item {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
hoverEnabled: true;
}
RalewayBold {

View file

@ -394,6 +394,7 @@ Item {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
hoverEnabled: true;
}
Image {

View file

@ -43,6 +43,7 @@ Item {
width: parent.width;
height: (root.shouldShowTopAndBottomOfWallet || root.shouldShowTopOfWallet) ? parent.height : parent.height - root.parentAppTitleBarHeight - root.parentAppNavBarHeight;
propagateComposedEvents: false;
hoverEnabled: true;
}
Connections {
@ -57,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';
}
@ -103,6 +107,12 @@ Item {
}
}
HifiCommerceCommon.CommerceLightbox {
id: lightboxPopup;
visible: false;
anchors.fill: parent;
}
// Send Money Home BEGIN
Item {
id: sendMoneyHome;
@ -326,6 +336,7 @@ Item {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
hoverEnabled: true;
}
ListModel {
@ -477,6 +488,7 @@ Item {
enabled: connectionsList.currentIndex !== index;
anchors.fill: parent;
propagateComposedEvents: false;
hoverEnabled: true;
onClicked: {
connectionsList.currentIndex = index;
}
@ -505,6 +517,7 @@ Item {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
hoverEnabled: true;
}
Rectangle {
@ -917,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
@ -967,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 {
@ -1059,6 +1110,7 @@ Item {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
hoverEnabled: true;
}
AnimatedImage {
@ -1533,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

View file

@ -2294,11 +2294,7 @@ void Application::initializeGL() {
#ifndef Q_OS_ANDROID
_renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraJob", cullFunctor, !DISABLE_DEFERRED);
#endif
_renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, !DISABLE_DEFERRED);
#ifdef Q_OS_OSX
DeadlockWatchdogThread::resume();
#endif
_renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, !DISABLE_DEFERRED, render::ItemKey::TAG_BITS_0, render::ItemKey::TAG_BITS_0);
_renderEngine->load();
_renderEngine->registerScene(_main3DScene);
@ -2306,6 +2302,10 @@ void Application::initializeGL() {
// 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());

View file

@ -178,7 +178,7 @@ public:
render::ItemID WorldBoxRenderData::_item{ render::Item::INVALID_ITEM_ID };
namespace render {
template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape(); }
template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1); }
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); }
template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) {
if (Menu::getInstance()->isOptionChecked(MenuOption::WorldAxes)) {

View file

@ -19,8 +19,9 @@
using RenderArgsPointer = std::shared_ptr<RenderArgs>;
void MainRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) {
task.addJob<RenderShadowTask>("RenderShadowTask", cullFunctor);
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor);
task.addJob<RenderShadowTask>("RenderShadowTask", cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1);
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1);
assert(items.canCast<RenderFetchCullSortTask::Output>());
if (!isDeferred) {
task.addJob<RenderForwardTask>("Forward", items);
@ -205,7 +206,7 @@ public:
void SecondaryCameraRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) {
const auto cachedArg = task.addJob<SecondaryCameraJob>("SecondaryCamera");
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor);
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1);
assert(items.canCast<RenderFetchCullSortTask::Output>());
if (!isDeferred) {
task.addJob<RenderForwardTask>("Forward", items);

View file

@ -48,6 +48,7 @@
#include <recording/Frame.h>
#include <RecordingScriptingInterface.h>
#include <trackers/FaceTracker.h>
#include <RenderableModelEntityItem.h>
#include "MyHead.h"
#include "MySkeletonModel.h"
@ -503,11 +504,42 @@ void MyAvatar::updateEyeContactTarget(float deltaTime) {
extern QByteArray avatarStateToFrame(const AvatarData* _avatar);
extern void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar);
void MyAvatar::beParentOfChild(SpatiallyNestablePointer newChild) const {
_cauterizationNeedsUpdate = true;
SpatiallyNestable::beParentOfChild(newChild);
}
void MyAvatar::forgetChild(SpatiallyNestablePointer newChild) const {
_cauterizationNeedsUpdate = true;
SpatiallyNestable::forgetChild(newChild);
}
void MyAvatar::updateChildCauterization(SpatiallyNestablePointer object) {
if (object->getNestableType() == NestableType::Entity) {
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
entity->setCauterized(!_prevShouldDrawHead);
}
}
void MyAvatar::simulate(float deltaTime) {
PerformanceTimer perfTimer("simulate");
animateScaleChanges(deltaTime);
if (_cauterizationNeedsUpdate) {
const std::unordered_set<int>& headBoneSet = _skeletonModel->getCauterizeBoneSet();
forEachChild([&](SpatiallyNestablePointer object) {
bool isChildOfHead = headBoneSet.find(object->getParentJointIndex()) != headBoneSet.end();
if (isChildOfHead) {
updateChildCauterization(object);
object->forEachDescendant([&](SpatiallyNestablePointer descendant) {
updateChildCauterization(descendant);
});
}
});
_cauterizationNeedsUpdate = false;
}
{
PerformanceTimer perfTimer("transform");
bool stepAction = false;
@ -1067,7 +1099,7 @@ void MyAvatar::setEnableDebugDrawIKChains(bool isEnabled) {
}
void MyAvatar::setEnableMeshVisible(bool isEnabled) {
_skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene());
_skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE);
}
void MyAvatar::setEnableInverseKinematics(bool isEnabled) {
@ -1417,8 +1449,9 @@ void MyAvatar::clearJointsData() {
void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
Avatar::setSkeletonModelURL(skeletonModelURL);
_skeletonModel->setVisibleInScene(true, qApp->getMain3DScene());
_skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE);
_headBoneSet.clear();
_cauterizationNeedsUpdate = true;
emit skeletonChanged();
}
@ -1762,7 +1795,7 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName,
void MyAvatar::setVisibleInSceneIfReady(Model* model, const render::ScenePointer& scene, bool visible) {
if (model->isActive() && model->isRenderable()) {
model->setVisibleInScene(visible, scene);
model->setVisibleInScene(visible, scene, render::ItemKey::TAG_BITS_NONE);
}
}
@ -1790,6 +1823,8 @@ void MyAvatar::initHeadBones() {
}
q.pop();
}
_cauterizationNeedsUpdate = true;
}
QUrl MyAvatar::getAnimGraphOverrideUrl() const {
@ -1860,6 +1895,7 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
_fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl();
initAnimGraph();
_isAnimatingScale = true;
_cauterizationNeedsUpdate = true;
}
if (_enableDebugDrawDefaultPose || _enableDebugDrawAnimPose) {
@ -1948,6 +1984,7 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) {
// toggle using the cauterizedBones depending on where the camera is and the rendering pass type.
const bool shouldDrawHead = shouldRenderHead(renderArgs);
if (shouldDrawHead != _prevShouldDrawHead) {
_cauterizationNeedsUpdate = true;
_skeletonModel->setEnableCauterization(!shouldDrawHead);
for (int i = 0; i < _attachmentData.size(); i++) {
@ -1957,7 +1994,8 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) {
_attachmentData[i].jointName.compare("RightEye", Qt::CaseInsensitive) == 0 ||
_attachmentData[i].jointName.compare("HeadTop_End", Qt::CaseInsensitive) == 0 ||
_attachmentData[i].jointName.compare("Face", Qt::CaseInsensitive) == 0) {
_attachmentModels[i]->setVisibleInScene(shouldDrawHead, qApp->getMain3DScene());
_attachmentModels[i]->setVisibleInScene(shouldDrawHead, qApp->getMain3DScene(),
render::ItemKey::TAG_BITS_NONE);
}
}
}

View file

@ -633,6 +633,11 @@ signals:
private slots:
void leaveDomain();
protected:
virtual void beParentOfChild(SpatiallyNestablePointer newChild) const override;
virtual void forgetChild(SpatiallyNestablePointer newChild) const override;
private:
bool requiresSafeLanding(const glm::vec3& positionIn, glm::vec3& positionOut);
@ -812,6 +817,8 @@ private:
bool _enableDebugDrawIKChains { false };
bool _enableDebugDrawDetailedCollision { false };
mutable bool _cauterizationNeedsUpdate; // do we need to scan children and update their "cauterized" state?
AudioListenerMode _audioListenerMode;
glm::vec3 _customListenPosition;
glm::quat _customListenOrientation;
@ -849,6 +856,8 @@ private:
// height of user in sensor space, when standing erect.
ThreadSafeValueCache<float> _userHeight { DEFAULT_AVATAR_HEIGHT };
void updateChildCauterization(SpatiallyNestablePointer object);
// max unscaled forward movement speed
ThreadSafeValueCache<float> _walkSpeed { DEFAULT_AVATAR_MAX_WALKING_SPEED };
};

View file

@ -86,7 +86,8 @@ void ModelOverlay::update(float deltatime) {
}
if (_visibleDirty) {
_visibleDirty = false;
_model->setVisibleInScene(getVisible(), scene);
// don't show overlays in mirrors
_model->setVisibleInScene(getVisible(), scene, render::ItemKey::TAG_BITS_0);
}
if (_drawInFrontDirty) {
_drawInFrontDirty = false;
@ -120,8 +121,10 @@ void ModelOverlay::removeFromScene(Overlay::Pointer overlay, const render::Scene
}
void ModelOverlay::setVisible(bool visible) {
Overlay::setVisible(visible);
_visibleDirty = true;
if (visible != getVisible()) {
Overlay::setVisible(visible);
_visibleDirty = true;
}
}
void ModelOverlay::setDrawInFront(bool drawInFront) {

View file

@ -106,7 +106,7 @@ private:
bool _jointMappingCompleted { false };
QVector<int> _jointMapping; // domain is index into model-joints, range is index into animation-joints
bool _visibleDirty { false };
bool _visibleDirty { true };
bool _drawInFrontDirty { false };
bool _drawInHUDDirty { false };

View file

@ -44,6 +44,13 @@ namespace render {
} else {
builder.withViewSpace();
}
if (!overlay->getVisible()) {
builder.withInvisible();
}
builder.withTagBits(render::ItemKey::TAG_BITS_0); // Only draw overlays in main view
return builder.build();
}
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay) {

View file

@ -50,7 +50,7 @@ const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f);
namespace render {
template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) {
return ItemKey::Builder::opaqueShape().withTypeMeta();
return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1);
}
template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar) {
return static_pointer_cast<Avatar>(avatar)->getBounds();

View file

@ -398,7 +398,7 @@ void HmdDisplayPlugin::HUDRenderer::updatePipeline() {
auto vs = hmd_ui_vert::getShader();
auto ps = hmd_ui_frag::getShader();
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());

View file

@ -159,10 +159,10 @@ Item::Bound EntityRenderer::getBound() {
ItemKey EntityRenderer::getKey() {
if (isTransparent()) {
return ItemKey::Builder::transparentShape().withTypeMeta();
return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
}
return ItemKey::Builder::opaqueShape().withTypeMeta();
return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
}
uint32_t EntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) {
@ -185,7 +185,12 @@ void EntityRenderer::render(RenderArgs* args) {
emit requestRenderUpdate();
}
if (_visible) {
auto& renderMode = args->_renderMode;
bool cauterized = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE &&
renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE &&
_cauterized);
if (_visible && !cauterized) {
doRender(args);
}
}
@ -366,6 +371,7 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa
_moving = entity->isMovingRelativeToParent();
_visible = entity->getVisible();
_cauterized = entity->getCauterized();
_needsRenderUpdate = false;
});
}

View file

@ -124,6 +124,7 @@ protected:
bool _isFading{ _entitiesShouldFadeFunction() };
bool _prevIsTransparent { false };
bool _visible { false };
bool _cauterized { false };
bool _moving { false };
bool _needsRenderUpdate { false };
// Only touched on the rendering thread

View file

@ -1013,9 +1013,9 @@ ModelEntityRenderer::ModelEntityRenderer(const EntityItemPointer& entity) : Pare
void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed) {
if (didVisualGeometryRequestSucceed) {
_itemKey = ItemKey::Builder().withTypeMeta();
_itemKey = ItemKey::Builder().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
} else {
_itemKey = ItemKey::Builder().withTypeMeta().withTypeShape();
_itemKey = ItemKey::Builder().withTypeMeta().withTypeShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
}
}
@ -1334,11 +1334,16 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
entity->updateModelBounds();
entity->stopModelOverrideIfNoParent();
if (model->isVisible() != _visible) {
// Default behavior for model is to not be visible in main view if cauterized (aka parented to the avatar's neck joint)
uint32_t viewTaskBits = _cauterized ?
render::ItemKey::TAG_BITS_1 : // draw in every view except the main one (view zero)
render::ItemKey::TAG_BITS_ALL; // draw in all views
if (model->isVisible() != _visible || model->getViewTagBits() != viewTaskBits) {
// FIXME: this seems like it could be optimized if we tracked our last known visible state in
// the renderable item. As it stands now the model checks it's visible/invisible state
// so most of the time we don't do anything in this function.
model->setVisibleInScene(_visible, scene);
model->setVisibleInScene(_visible, scene, viewTaskBits);
}
// TODO? early exit here when not visible?

View file

@ -147,9 +147,9 @@ void ParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEn
ItemKey ParticleEffectEntityRenderer::getKey() {
if (_visible) {
return ItemKey::Builder::transparentShape();
return ItemKey::Builder::transparentShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
} else {
return ItemKey::Builder().withInvisible().build();
return ItemKey::Builder().withInvisible().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1).build();
}
}

View file

@ -112,7 +112,7 @@ PolyLineEntityRenderer::PolyLineEntityRenderer(const EntityItemPointer& entity)
}
ItemKey PolyLineEntityRenderer::getKey() {
return ItemKey::Builder::transparentShape().withTypeMeta();
return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
}
ShapeKey PolyLineEntityRenderer::getShapeKey() {

View file

@ -101,7 +101,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.
@ -1140,7 +1140,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;

View file

@ -269,7 +269,7 @@ void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointe
ItemKey ZoneEntityRenderer::getKey() {
return ItemKey::Builder().withTypeMeta().build();
return ItemKey::Builder().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1).build();
}
bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {

View file

@ -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;
});
}

View file

@ -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);
@ -470,6 +474,9 @@ public:
static QString _marketplacePublicKey;
static void retrieveMarketplacePublicKey();
void setCauterized(bool value) { _cauterized = value; }
bool getCauterized() const { return _cauterized; }
signals:
void requestRenderUpdate();
@ -572,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
@ -623,6 +630,7 @@ protected:
quint64 _lastUpdatedAccelerationTimestamp { 0 };
quint64 _lastUpdatedQueryAACubeTimestamp { 0 };
bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera
};
#endif // hifi_EntityItem_h

View file

@ -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);
}

View file

@ -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;
}
});
}

View file

@ -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

View file

@ -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;

View file

@ -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);
}

View file

@ -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] =

View file

@ -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 {

View file

@ -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());

View file

@ -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;
}

View file

@ -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,

View file

@ -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);
}

View file

@ -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 {

View file

@ -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());

View file

@ -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;
}

View file

@ -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,

View file

@ -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;
}

View file

@ -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;

View file

@ -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++;
}

View file

@ -15,6 +15,7 @@
#include <string>
#include <memory>
#include <set>
#include <map>
#include <QUrl>
@ -22,6 +23,8 @@ 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;

View file

@ -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() { }

View file

@ -68,7 +68,7 @@ public:
typedef render::Payload<AnimDebugDrawData> AnimDebugDrawPayload;
namespace render {
template <> const ItemKey payloadGetKey(const AnimDebugDrawData::Pointer& data) { return (data->_isVisible ? ItemKey::Builder::opaqueShape() : ItemKey::Builder::opaqueShape().withInvisible()); }
template <> const ItemKey payloadGetKey(const AnimDebugDrawData::Pointer& data) { return (data->_isVisible ? ItemKey::Builder::opaqueShape() : ItemKey::Builder::opaqueShape().withInvisible()).withTagBits(ItemKey::TAG_BITS_ALL); }
template <> const Item::Bound payloadGetBound(const AnimDebugDrawData::Pointer& data) { return data->_bound; }
template <> void payloadRender(const AnimDebugDrawData::Pointer& data, RenderArgs* args) {
data->render(args);

View file

@ -249,7 +249,7 @@ void CauterizedModel::updateRenderItems() {
data.updateTransformForCauterizedMesh(renderTransform);
data.setEnableCauterization(enableCauterization);
data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::TAG_BITS_ALL);
data.setLayer(isLayeredInFront, isLayeredInHUD);
data.setShapeKey(invalidatePayloadShapeKey, isWireframe);
});

View file

@ -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,

View file

@ -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@>

View file

@ -18,9 +18,13 @@ namespace render {
template <> const ItemKey payloadGetKey(const LightPayload::Pointer& payload) {
ItemKey::Builder builder;
builder.withTypeLight();
if (!payload || !payload->isVisible()) {
builder.withInvisible();
builder.withTagBits(ItemKey::TAG_BITS_ALL);
if (payload) {
if (!payload->isVisible()) {
builder.withInvisible();
}
}
return builder.build();
}
@ -87,6 +91,7 @@ namespace render {
template <> const ItemKey payloadGetKey(const KeyLightPayload::Pointer& payload) {
ItemKey::Builder builder;
builder.withTypeLight();
builder.withTagBits(ItemKey::TAG_BITS_ALL);
if (!payload || !payload->isVisible()) {
builder.withInvisible();
}

View file

@ -71,10 +71,20 @@ void MeshPartPayload::updateMaterial(graphics::MaterialPointer drawMaterial) {
_drawMaterial = drawMaterial;
}
ItemKey MeshPartPayload::getKey() const {
void MeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits) {
ItemKey::Builder builder;
builder.withTypeShape();
if (!isVisible) {
builder.withInvisible();
}
builder.withTagBits(tagBits);
if (isLayered) {
builder.withLayered();
}
if (_drawMaterial) {
auto matKey = _drawMaterial->getKey();
if (matKey.isTranslucent()) {
@ -82,7 +92,11 @@ ItemKey MeshPartPayload::getKey() const {
}
}
return builder.build();
_itemKey = builder.build();
}
ItemKey MeshPartPayload::getKey() const {
return _itemKey;
}
Item::Bound MeshPartPayload::getBound() const {
@ -389,7 +403,7 @@ void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& render
_worldBound.transform(boundTransform);
}
void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered) {
void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits) {
ItemKey::Builder builder;
builder.withTypeShape();
@ -397,6 +411,8 @@ void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered) {
builder.withInvisible();
}
builder.withTagBits(tagBits);
if (isLayered) {
builder.withLayered();
}
@ -415,10 +431,6 @@ void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered) {
_itemKey = builder.build();
}
ItemKey ModelMeshPartPayload::getKey() const {
return _itemKey;
}
void ModelMeshPartPayload::setLayer(bool isLayeredInFront, bool isLayeredInHUD) {
if (isLayeredInFront) {
_layer = Item::LAYER_3D_FRONT;

View file

@ -33,6 +33,8 @@ public:
typedef render::Payload<MeshPartPayload> Payload;
typedef Payload::DataPointer Pointer;
virtual void updateKey(bool isVisible, bool isLayered, uint8_t tagBits);
virtual void updateMeshPart(const std::shared_ptr<const graphics::Mesh>& drawMesh, int partIndex);
virtual void notifyLocationChanged() {}
@ -70,6 +72,9 @@ public:
size_t getMaterialTextureSize() { return _drawMaterial ? _drawMaterial->getTextureSize() : 0; }
int getMaterialTextureCount() { return _drawMaterial ? _drawMaterial->getTextureCount() : 0; }
bool hasTextureInfo() const { return _drawMaterial ? _drawMaterial->hasTextureInfo() : false; }
protected:
render::ItemKey _itemKey{ render::ItemKey::Builder::opaqueShape().build() };
};
namespace render {
@ -94,16 +99,15 @@ public:
using TransformType = glm::mat4;
#endif
void updateKey(bool isVisible, bool isLayered, uint8_t tagBits) override;
void updateClusterBuffer(const std::vector<TransformType>& clusterTransforms);
void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform);
// Render Item interface
render::ItemKey getKey() const override;
int getLayer() const;
render::ShapeKey getShapeKey() const override; // shape interface
void render(RenderArgs* args) override;
void setKey(bool isVisible, bool isLayered);
void setLayer(bool isLayeredInFront, bool isLayeredInHUD);
void setShapeKey(bool invalidateShapeKey, bool isWireframe);
@ -126,7 +130,6 @@ private:
void initCache(const ModelPointer& model);
gpu::BufferPointer _blendedVertexBuffer;
render::ItemKey _itemKey { render::ItemKey::Builder::opaqueShape().build() };
render::ShapeKey _shapeKey { render::ShapeKey::Builder::invalid() };
int _layer { render::Item::LAYER_3D };
};

View file

@ -268,6 +268,7 @@ void Model::updateRenderItems() {
bool isWireframe = self->isWireframe();
bool isVisible = self->isVisible();
uint8_t viewTagBits = self->getViewTagBits();
bool isLayeredInFront = self->isLayeredInFront();
bool isLayeredInHUD = self->isLayeredInHUD();
@ -280,8 +281,10 @@ void Model::updateRenderItems() {
bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, clusterTransforms, invalidatePayloadShapeKey,
isWireframe, isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, clusterTransforms,
invalidatePayloadShapeKey, isWireframe, isVisible,
viewTagBits, isLayeredInFront,
isLayeredInHUD](ModelMeshPartPayload& data) {
data.updateClusterBuffer(clusterTransforms);
Transform renderTransform = modelTransform;
@ -297,7 +300,7 @@ void Model::updateRenderItems() {
}
data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits);
data.setLayer(isLayeredInFront, isLayeredInHUD);
data.setShapeKey(invalidatePayloadShapeKey, isWireframe);
});
@ -681,22 +684,25 @@ void Model::calculateTriangleSets() {
}
}
void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene) {
if (_isVisible != isVisible) {
void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewTagBits) {
if (_isVisible != isVisible || _viewTagBits != viewTagBits) {
_isVisible = isVisible;
_viewTagBits = viewTagBits;
bool isLayeredInFront = _isLayeredInFront;
bool isLayeredInHUD = _isLayeredInHUD;
render::Transaction transaction;
foreach (auto item, _modelMeshRenderItemsMap.keys()) {
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront,
isLayeredInHUD](ModelMeshPartPayload& data) {
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits);
});
}
foreach(auto item, _collisionRenderItemsMap.keys()) {
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront,
isLayeredInHUD](ModelMeshPartPayload& data) {
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits);
});
}
scene->enqueueTransaction(transaction);
@ -709,18 +715,21 @@ void Model::setLayeredInFront(bool isLayeredInFront, const render::ScenePointer&
_isLayeredInFront = isLayeredInFront;
bool isVisible = _isVisible;
uint8_t viewTagBits = _viewTagBits;
bool isLayeredInHUD = _isLayeredInHUD;
render::Transaction transaction;
foreach(auto item, _modelMeshRenderItemsMap.keys()) {
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront,
isLayeredInHUD](ModelMeshPartPayload& data) {
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits);
data.setLayer(isLayeredInFront, isLayeredInHUD);
});
}
foreach(auto item, _collisionRenderItemsMap.keys()) {
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront,
isLayeredInHUD](ModelMeshPartPayload& data) {
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits);
data.setLayer(isLayeredInFront, isLayeredInHUD);
});
}
@ -733,18 +742,21 @@ void Model::setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& sce
_isLayeredInHUD = isLayeredInHUD;
bool isVisible = _isVisible;
uint8_t viewTagBits = _viewTagBits;
bool isLayeredInFront = _isLayeredInFront;
render::Transaction transaction;
foreach(auto item, _modelMeshRenderItemsMap.keys()) {
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront,
isLayeredInHUD](ModelMeshPartPayload& data) {
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits);
data.setLayer(isLayeredInFront, isLayeredInHUD);
});
}
foreach(auto item, _collisionRenderItemsMap.keys()) {
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront,
isLayeredInHUD](ModelMeshPartPayload& data) {
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits);
data.setLayer(isLayeredInFront, isLayeredInHUD);
});
}

View file

@ -86,7 +86,7 @@ public:
const QUrl& getURL() const { return _url; }
// new Scene/Engine rendering support
void setVisibleInScene(bool isVisible, const render::ScenePointer& scene);
void setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewTagBits);
void setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene);
void setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene);
bool needsFixupInScene() const;
@ -104,6 +104,7 @@ public:
bool isRenderable() const;
bool isVisible() const { return _isVisible; }
uint8_t getViewTagBits() const { return _viewTagBits; }
bool isLayeredInFront() const { return _isLayeredInFront; }
bool isLayeredInHUD() const { return _isLayeredInHUD; }
@ -396,6 +397,7 @@ protected:
QUrl _url;
bool _isVisible;
uint8_t _viewTagBits{ render::ItemKey::TAG_BITS_ALL };
gpu::Buffers _blendedVertexBuffers;

View file

@ -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 = model_lightmap_vert::getShader();
auto modelLightmapNormalMapVertex = model_lightmap_normal_map_vert::getShader();
auto modelTranslucentVertex = model_translucent_vert::getShader();
auto modelTranslucentFadeVertex = model_translucent_fade_vert::getShader();
auto modelTranslucentNormalMapVertex = model_translucent_normal_map_vert::getShader();
auto modelShadowVertex = model_shadow_vert::getShader();
auto skinModelVertex = skin_model_vert::getShader();
auto skinModelNormalMapVertex = skin_model_normal_map_vert::getShader();
@ -220,6 +222,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
auto modelSpecularMapPixel = model_specular_map_frag::getShader();
auto modelNormalSpecularMapPixel = model_normal_specular_map_frag::getShader();
auto modelTranslucentPixel = model_translucent_frag::getShader();
auto modelTranslucentNormalMapPixel = model_translucent_normal_map_frag::getShader();
auto modelTranslucentUnlitPixel = model_translucent_unlit_frag::getShader();
auto modelShadowPixel = model_shadow_frag::getShader();
auto modelLightmapPixel = model_lightmap_frag::getShader();
@ -238,6 +241,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip
auto modelNormalSpecularMapFadePixel = model_normal_specular_map_fade_frag::getShader();
auto modelShadowFadePixel = model_shadow_fade_frag::getShader();
auto modelTranslucentFadePixel = model_translucent_fade_frag::getShader();
auto modelTranslucentNormalMapFadePixel = model_translucent_normal_map_fade_frag::getShader();
auto modelTranslucentUnlitFadePixel = model_translucent_unlit_fade_frag::getShader();
auto simpleFadePixel = simple_textured_fade_frag::getShader();
auto simpleUnlitFadePixel = simple_textured_unlit_fade_frag::getShader();
@ -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(

View file

@ -200,7 +200,7 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, con
});
}
void RenderShadowTask::build(JobModel& task, const render::Varying& input, render::Varying& output, CullFunctor cullFunctor) {
void RenderShadowTask::build(JobModel& task, const render::Varying& input, render::Varying& output, CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) {
cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&) { return true; };
// Prepare the ShapePipeline
@ -216,7 +216,7 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
task.addJob<RenderShadowSetup>("ShadowSetup");
for (auto i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) {
const auto setupOutput = task.addJob<RenderShadowCascadeSetup>("ShadowCascadeSetup", i);
const auto setupOutput = task.addJob<RenderShadowCascadeSetup>("ShadowCascadeSetup", i, tagBits, tagMask);
const auto shadowFilter = setupOutput.getN<RenderShadowCascadeSetup::Outputs>(1);
// CPU jobs:
@ -264,7 +264,7 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon
const auto globalShadow = lightStage->getCurrentKeyShadow();
if (globalShadow && _cascadeIndex<globalShadow->getCascadeCount()) {
output.edit1() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered();
output.edit1() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(_tagBits, _tagMask);
globalShadow->setKeylightCascadeFrustum(_cascadeIndex, args->getViewFrustum(), SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR);

View file

@ -48,7 +48,7 @@ public:
using JobModel = render::Task::Model<RenderShadowTask, Config>;
RenderShadowTask() {}
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor shouldRender);
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor shouldRender, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00);
void configure(const Config& configuration);
};
@ -67,12 +67,14 @@ public:
using Outputs = render::VaryingSet3<RenderArgs::RenderMode, render::ItemFilter, float>;
using JobModel = render::Job::ModelO<RenderShadowCascadeSetup, Outputs>;
RenderShadowCascadeSetup(unsigned int cascadeIndex) : _cascadeIndex{ cascadeIndex } {}
RenderShadowCascadeSetup(unsigned int cascadeIndex, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00) : _cascadeIndex{ cascadeIndex }, _tagBits(tagBits), _tagMask(tagMask) {}
void run(const render::RenderContextPointer& renderContext, Outputs& output);
private:
unsigned int _cascadeIndex;
uint8_t _tagBits{ 0x00 };
uint8_t _tagMask{ 0x00 };
};
class RenderShadowCascadeTeardown {

View file

@ -14,7 +14,7 @@
#include "RenderDeferredTask.h"
#include "RenderForwardTask.h"
void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, bool isDeferred) {
void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, bool isDeferred, uint8_t tagBits, uint8_t tagMask) {
// auto items = input.get<Input>();
// Shadows use an orthographic projection because they are linked to sunlights
@ -28,9 +28,9 @@ void RenderViewTask::build(JobModel& task, const render::Varying& input, render:
const auto threshold = 1e-3f;
return relativeBoundRadius > threshold;
return true;
});
}, tagBits, tagMask);
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor);
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, tagBits, tagMask);
assert(items.canCast<RenderFetchCullSortTask::Output>());
if (isDeferred) {

View file

@ -23,7 +23,7 @@ public:
RenderViewTask() {}
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred);
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00);
};

View file

@ -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)$>;

View file

@ -16,7 +16,7 @@
<@include DeferredGlobalLight.slh@>
<$declareEvalGlobalLightingAlphaBlended()$>
<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
<@include LightLocal.slh@>

View file

@ -16,7 +16,7 @@
<@include DeferredGlobalLight.slh@>
<$declareEvalGlobalLightingAlphaBlended()$>
<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
<@include LightLocal.slh@>

View 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);
}

View file

@ -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)$>
}

View 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);
}

View file

@ -11,7 +11,7 @@
//
<@include DeferredGlobalLight.slh@>
<$declareEvalGlobalLightingAlphaBlended()$>
<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
<@include graphics/Material.slh@>

View file

@ -16,7 +16,7 @@
<@include DeferredBufferWrite.slh@>
<@include DeferredGlobalLight.slh@>
<$declareEvalGlobalLightingAlphaBlended()$>
<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
<@include gpu/Transform.slh@>
<$declareStandardCameraTransform()$>

View file

@ -16,7 +16,7 @@
<@include DeferredBufferWrite.slh@>
<@include DeferredGlobalLight.slh@>
<$declareEvalGlobalLightingAlphaBlended()$>
<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
<@include gpu/Transform.slh@>
<$declareStandardCameraTransform()$>

View file

@ -61,7 +61,7 @@ void render::cullItems(const RenderContextPointer& renderContext, const CullFunc
details._rendered += (int)outItems.size();
}
void FetchNonspatialItems::run(const RenderContextPointer& renderContext, ItemBounds& outItems) {
void FetchNonspatialItems::run(const RenderContextPointer& renderContext, const ItemFilter& filter, ItemBounds& outItems) {
assert(renderContext->args);
assert(renderContext->args->hasViewFrustum());
auto& scene = renderContext->_scene;
@ -72,7 +72,9 @@ void FetchNonspatialItems::run(const RenderContextPointer& renderContext, ItemBo
outItems.reserve(items.size());
for (auto& id : items) {
auto& item = scene->getItem(id);
outItems.emplace_back(ItemBound(id, item.getBound()));
if (filter.test(item.getKey())) {
outItems.emplace_back(ItemBound(id, item.getBound()));
}
}
}

View file

@ -24,8 +24,8 @@ namespace render {
class FetchNonspatialItems {
public:
using JobModel = Job::ModelO<FetchNonspatialItems, ItemBounds>;
void run(const RenderContextPointer& renderContext, ItemBounds& outItems);
using JobModel = Job::ModelIO<FetchNonspatialItems, ItemFilter, ItemBounds>;
void run(const RenderContextPointer& renderContext, const ItemFilter& filter, ItemBounds& outItems);
};
class FetchSpatialTreeConfig : public Job::Config {

View file

@ -34,6 +34,21 @@ const int Item::LAYER_3D = 1;
const int Item::LAYER_3D_FRONT = 2;
const int Item::LAYER_3D_HUD = 3;
const uint8_t ItemKey::TAG_BITS_ALL { 0xFF };
const uint8_t ItemKey::TAG_BITS_NONE { 0x00 };
const uint8_t ItemKey::TAG_BITS_0 { 0x01 };
const uint8_t ItemKey::TAG_BITS_1 { 0x02 };
const uint8_t ItemKey::TAG_BITS_2 { 0x04 };
const uint8_t ItemKey::TAG_BITS_3 { 0x08 };
const uint8_t ItemKey::TAG_BITS_4 { 0x10 };
const uint8_t ItemKey::TAG_BITS_5 { 0x20 };
const uint8_t ItemKey::TAG_BITS_6 { 0x40 };
const uint8_t ItemKey::TAG_BITS_7 { 0x80 };
const uint32_t ItemKey::KEY_TAG_BITS_MASK = ((uint32_t) ItemKey::TAG_BITS_ALL) << FIRST_TAG_BIT;
void Item::Status::Value::setScale(float scale) {
_scale = (std::numeric_limits<unsigned short>::max() -1) * 0.5f * (1.0f + std::max(std::min(scale, 1.0f), 0.0f));
}

View file

@ -38,25 +38,62 @@ class Context;
// Key is the KEY to filter Items and create specialized lists
class ItemKey {
public:
enum FlagBit {
// 8 tags are available to organize the items and filter them against as fields of the ItemKey.
// TAG & TAG_BITS are defined from several bits in the Key.
// An Item can be tagged and filtering can rely on the tags to keep or exclude items
// ItemKey are not taged by default
enum Tag : uint8_t {
TAG_0 = 0, // 8 Tags
TAG_1,
TAG_2,
TAG_3,
TAG_4,
TAG_5,
TAG_6,
TAG_7,
NUM_TAGS
};
// Tag bits are derived from the Tag enum
const static uint8_t TAG_BITS_ALL;
const static uint8_t TAG_BITS_NONE;
const static uint8_t TAG_BITS_0;
const static uint8_t TAG_BITS_1;
const static uint8_t TAG_BITS_2;
const static uint8_t TAG_BITS_3;
const static uint8_t TAG_BITS_4;
const static uint8_t TAG_BITS_5;
const static uint8_t TAG_BITS_6;
const static uint8_t TAG_BITS_7;
enum FlagBit : uint32_t {
TYPE_SHAPE = 0, // Item is a Shape
TYPE_LIGHT, // Item is a Light
TYPE_META, // Item is a Meta: meanning it s used to represent a higher level object, potentially represented by other render items
TRANSLUCENT, // Transparent and not opaque, for some odd reason TRANSPARENCY doesn't work...
VIEW_SPACE, // Transformed in view space, and not in world space
DYNAMIC, // Dynamic and bound will change unlike static item
DEFORMED, // Deformed within bound, not solid
INVISIBLE, // Visible or not? could be just here to cast shadow
INVISIBLE, // Visible or not in the scene?
SHADOW_CASTER, // Item cast shadows
PICKABLE, // Item can be picked/selected
LAYERED, // Item belongs to one of the layers different from the default layer
SMALLER,
FIRST_TAG_BIT, // 8 Tags available to organize the items and filter them against
LAST_TAG_BIT = FIRST_TAG_BIT + NUM_TAGS,
__SMALLER, // Reserved bit for spatialized item to indicate that it is smaller than expected in the cell in which it belongs (probably because it overlaps over several smaller cells)
NUM_FLAGS, // Not a valid flag
};
typedef std::bitset<NUM_FLAGS> Flags;
// All the bits touching tag bits sets to true
const static uint32_t KEY_TAG_BITS_MASK;
static uint32_t evalTagBitsWithKeyBits(uint8_t tagBits, const uint32_t keyBits) {
return (keyBits & ~KEY_TAG_BITS_MASK) | (((uint32_t)tagBits) << FIRST_TAG_BIT);
}
// The key is the Flags
Flags _flags;
@ -84,9 +121,12 @@ public:
Builder& withDeformed() { _flags.set(DEFORMED); return (*this); }
Builder& withInvisible() { _flags.set(INVISIBLE); return (*this); }
Builder& withShadowCaster() { _flags.set(SHADOW_CASTER); return (*this); }
Builder& withPickable() { _flags.set(PICKABLE); return (*this); }
Builder& withLayered() { _flags.set(LAYERED); return (*this); }
Builder& withTag(Tag tag) { _flags.set(FIRST_TAG_BIT + tag); return (*this); }
// Set ALL the tags in one call using the Tag bits
Builder& withTagBits(uint8_t tagBits) { _flags = evalTagBitsWithKeyBits(tagBits, _flags.to_ulong()); return (*this); }
// Convenient standard keys that we will keep on using all over the place
static Builder opaqueShape() { return Builder().withTypeShape(); }
static Builder transparentShape() { return Builder().withTypeShape().withTransparent(); }
@ -116,14 +156,15 @@ public:
bool isShadowCaster() const { return _flags[SHADOW_CASTER]; }
bool isPickable() const { return _flags[PICKABLE]; }
bool isLayered() const { return _flags[LAYERED]; }
bool isSpatial() const { return !isLayered(); }
bool isTag(Tag tag) const { return _flags[FIRST_TAG_BIT + tag]; }
uint8_t getTagBits() const { return ((_flags.to_ulong() & KEY_TAG_BITS_MASK) >> FIRST_TAG_BIT); }
// Probably not public, flags used by the scene
bool isSmall() const { return _flags[SMALLER]; }
void setSmaller(bool smaller) { (smaller ? _flags.set(SMALLER) : _flags.reset(SMALLER)); }
bool isSmall() const { return _flags[__SMALLER]; }
void setSmaller(bool smaller) { (smaller ? _flags.set(__SMALLER) : _flags.reset(__SMALLER)); }
bool operator==(const ItemKey& key) { return (_flags == key._flags); }
bool operator!=(const ItemKey& key) { return (_flags != key._flags); }
@ -177,11 +218,14 @@ public:
Builder& withNoShadowCaster() { _value.reset(ItemKey::SHADOW_CASTER); _mask.set(ItemKey::SHADOW_CASTER); return (*this); }
Builder& withShadowCaster() { _value.set(ItemKey::SHADOW_CASTER); _mask.set(ItemKey::SHADOW_CASTER); return (*this); }
Builder& withPickable() { _value.set(ItemKey::PICKABLE); _mask.set(ItemKey::PICKABLE); return (*this); }
Builder& withoutLayered() { _value.reset(ItemKey::LAYERED); _mask.set(ItemKey::LAYERED); return (*this); }
Builder& withLayered() { _value.set(ItemKey::LAYERED); _mask.set(ItemKey::LAYERED); return (*this); }
Builder& withoutTag(ItemKey::Tag tagIndex) { _value.reset(ItemKey::FIRST_TAG_BIT + tagIndex); _mask.set(ItemKey::FIRST_TAG_BIT + tagIndex); return (*this); }
Builder& withTag(ItemKey::Tag tagIndex) { _value.set(ItemKey::FIRST_TAG_BIT + tagIndex); _mask.set(ItemKey::FIRST_TAG_BIT + tagIndex); return (*this); }
// Set ALL the tags in one call using the Tag bits and the Tag bits touched
Builder& withTagBits(uint8_t tagBits, uint8_t tagMask) { _value = ItemKey::evalTagBitsWithKeyBits(tagBits, _value.to_ulong()); _mask = ItemKey::evalTagBitsWithKeyBits(tagMask, _mask.to_ulong()); return (*this); }
Builder& withNothing() { _value.reset(); _mask.reset(); return (*this); }
// Convenient standard keys that we will keep on using all over the place

View file

@ -17,19 +17,21 @@
using namespace render;
void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varying& output, CullFunctor cullFunctor) {
void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varying& output, CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) {
cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; };
// CPU jobs:
// Fetch and cull the items from the scene
const ItemFilter filter = ItemFilter::Builder::visibleWorldItems().withoutLayered();
const ItemFilter filter = ItemFilter::Builder::visibleWorldItems().withoutLayered().withTagBits(tagBits, tagMask);
const auto spatialFilter = render::Varying(filter);
const auto spatialSelection = task.addJob<FetchSpatialTree>("FetchSceneSelection", spatialFilter);
const auto cullInputs = CullSpatialSelection::Inputs(spatialSelection, spatialFilter).asVarying();
const auto culledSpatialSelection = task.addJob<CullSpatialSelection>("CullSceneSelection", cullInputs, cullFunctor, RenderDetails::ITEM);
// Overlays are not culled
const auto nonspatialSelection = task.addJob<FetchNonspatialItems>("FetchOverlaySelection");
const ItemFilter overlayfilter = ItemFilter::Builder().withVisible().withTagBits(tagBits, tagMask);
const auto nonspatialFilter = render::Varying(overlayfilter);
const auto nonspatialSelection = task.addJob<FetchNonspatialItems>("FetchOverlaySelection", nonspatialFilter);
// Multi filter visible items into different buckets
const int NUM_SPATIAL_FILTERS = 4;

View file

@ -36,7 +36,7 @@ public:
RenderFetchCullSortTask() {}
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor);
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00);
};
#endif // hifi_RenderFetchCullSortTask_h

View file

@ -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));

View file

@ -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";

View file

@ -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) {

View file

@ -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:

View file

@ -300,7 +300,7 @@
if (visible) {
x = ((Date.now() / 1000) % ANIMATION_SECONDS_PER_REPEAT) / ANIMATION_SECONDS_PER_REPEAT;
if (isHMD) {
if (!isHMD) {
x = x * barDesktop.repeat;
} else {
x = x * BAR_HMD_REPEAT;
@ -309,9 +309,9 @@
// Update progress bar
Overlays.editOverlay(barDesktop.overlay, {
visible: !isHMD,
subImage: {
bounds: {
x: barDesktop.repeat - x,
y: 0,
y: windowHeight - barDesktop.height,
width: barDesktop.width - barDesktop.repeat,
height: barDesktop.height
}
@ -319,9 +319,9 @@
Overlays.editOverlay(barHMD.overlay, {
visible: isHMD,
subImage: {
bounds: {
x: BAR_HMD_REPEAT - x,
y: 0,
y: windowHeight - BAR_HMD_HEIGHT,
width: BAR_HMD_WIDTH - BAR_HMD_REPEAT,
height: BAR_HMD_HEIGHT
}

View file

@ -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");
}