diff options
Diffstat (limited to 'src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp')
-rw-r--r-- | src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp | 709 |
1 files changed, 513 insertions, 196 deletions
diff --git a/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp b/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp index ac3c3b31..f2627e05 100644 --- a/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp +++ b/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp @@ -92,6 +92,11 @@ #include "StudioProjectSettings.h" #include "StudioApp.h" #include "StudioUtils.h" +#include "Qt3DSDMHandles.h" +#include "IStudioRenderer.h" +#include "Qt3DSRenderBufferManager.h" +#include "Qt3DSRenderDynamicObjectSystem.h" +#include "Qt3DSRenderUIPSharedTranslation.h" namespace { @@ -155,7 +160,7 @@ class CDocEditor : public Q3DStudio::IInternalDocumentEditor ISlideSystem &m_SlideSystem; ISlideCore &m_SlideCore; ISlideGraphCore &m_SlideGraphCore; - IAnimationCore &m_AnimationCore; + IAnimationCore &m_animCore; CClientDataModelBridge &m_Bridge; IPropertySystem &m_PropertySystem; IMetaData &m_MetaData; @@ -182,7 +187,7 @@ public: , m_SlideSystem(*m_StudioSystem.GetFullSystem()->GetSlideSystem()) , m_SlideCore(*m_StudioSystem.GetFullSystem()->GetCoreSystem()->GetSlideCore()) , m_SlideGraphCore(*m_StudioSystem.GetFullSystem()->GetCoreSystem()->GetSlideGraphCore()) - , m_AnimationCore(*m_StudioSystem.GetFullSystem()->GetAnimationCore()) + , m_animCore(*m_StudioSystem.GetFullSystem()->GetAnimationCore()) , m_Bridge(*m_StudioSystem.GetClientDataModelBridge()) , m_PropertySystem(*m_StudioSystem.GetPropertySystem()) , m_MetaData(*m_StudioSystem.GetActionMetaData()) @@ -241,7 +246,7 @@ public: Qt3DSDMSlideHandle theMaster = theSlideInfo.m_MasterSlide; Qt3DSDMSlideHandle theActiveSlide = theSlideInfo.m_ActiveSlide; if (theAssociatedSlide == theMaster || theAssociatedSlide == theActiveSlide) { - long theViewTime = theSlideInfo.m_ComponentMilliseconds; + long theViewTime = theSlideInfo.m_ComponentTime; return eyeballVal && theStart <= theViewTime && theEnd > 0 && theEnd >= theViewTime; } } @@ -287,7 +292,8 @@ public: if (m_SlideCore.GetSpecificInstancePropertyValue(theAssociatedSlide, instance, inProperty, theGuid) || m_DataCore.GetInstancePropertyValue(instance, inProperty, theGuid)) { - return m_Bridge.GetInstanceByGUID(get<SLong4>(theGuid)); + if (theGuid.getType() == qt3dsdm::DataModelDataType::Long4) + return m_Bridge.GetInstanceByGUID(get<SLong4>(theGuid)); } return TInstanceHandle(); } @@ -423,7 +429,7 @@ public: void GetPathToInstanceMap(TCharPtrToSlideInstanceMap &outInstanceMap, qt3dsdm::Qt3DSDMPropertyHandle property, - bool checkMaterialContainers = true, + bool skipMaterialContainers = true, bool includeIdentifiers = true) const { SComposerObjectDefinitions &theDefinitions(m_Bridge.GetObjectDefinitions()); @@ -434,7 +440,7 @@ public: for (size_t idx = 0, end = existing.size(); idx < end; ++idx) { Qt3DSDMInstanceHandle theAsset(existing[idx]); - if (checkMaterialContainers && m_Bridge.isInsideMaterialContainer(theAsset)) + if (skipMaterialContainers && m_Bridge.isInsideMaterialContainer(theAsset)) continue; thePaths.clear(); @@ -457,12 +463,12 @@ public: } void GetSourcePathToInstanceMap(TCharPtrToSlideInstanceMap &outInstanceMap, - bool checkMaterialContainers = true, + bool skipMaterialContainers = true, bool includeIdentifiers = true) const override { SComposerObjectDefinitions &theDefinitions(m_Bridge.GetObjectDefinitions()); GetPathToInstanceMap(outInstanceMap, theDefinitions.m_Asset.m_SourcePath, - checkMaterialContainers, includeIdentifiers); + skipMaterialContainers, includeIdentifiers); } void GetImportPathToInstanceMap(TCharPtrToSlideInstanceMap &outInstanceMap) const override @@ -666,7 +672,7 @@ public: theSlide = m_SlideSystem.GetMasterSlide(theSlide); inSlide = theSlide; } - return m_AnimationCore.GetAnimation(inSlide, instance, propHdl, subIndex).Valid(); + return m_animCore.GetAnimation(inSlide, instance, propHdl, subIndex).Valid(); } bool IsAnimationArtistEdited(TSlideHandle inSlide, Qt3DSDMInstanceHandle instance, @@ -690,14 +696,14 @@ public: } Qt3DSDMAnimationHandle animHandle = - m_AnimationCore.GetAnimation(inSlide, instance, propHdl, subIndex); + m_animCore.GetAnimation(inSlide, instance, propHdl, subIndex); if (animHandle.Valid() == false) return false; - return m_AnimationCore.IsArtistEdited(animHandle); + return m_animCore.IsArtistEdited(animHandle); } pair<std::shared_ptr<qt3dsdm::IDOMWriter>, CFilePath> - DoCopySceneGraphObject(const TInstanceHandleList &inInstances) + DoCopySceneGraphObject(const TInstanceHandleList &inInstances, bool preserveFileIds) { if (inInstances.empty()) return pair<std::shared_ptr<qt3dsdm::IDOMWriter>, CFilePath>(); @@ -705,7 +711,8 @@ public: std::shared_ptr<IDOMWriter> theWriter(m_Doc.CreateDOMWriter()); TInstanceHandleList theInstances = ToGraphOrdering(inInstances); m_Doc.CreateSerializer()->SerializeSceneGraphObjects(*theWriter, theInstances, - GetActiveSlide(inInstances[0])); + GetActiveSlide(inInstances[0]), + preserveFileIds); CFilePath theFile = WriteWriterToFile(*theWriter, L"SceneGraph"); return make_pair(theWriter, theFile); } @@ -714,7 +721,7 @@ public: std::shared_ptr<qt3dsdm::IDOMReader> CopySceneGraphObjectsToMemory(const qt3dsdm::TInstanceHandleList &instanceList) { - return DoCopySceneGraphObject(instanceList).first->CreateDOMReader(); + return DoCopySceneGraphObject(instanceList, false).first->CreateDOMReader(); } // Exposed through document reader interface @@ -760,7 +767,7 @@ public: return theFinalPath; } - CFilePath CopySceneGraphObjects(TInstanceHandleList inInstances) override + CFilePath CopySceneGraphObjects(TInstanceHandleList inInstances, bool preserveFileIds) override { if (inInstances.empty()) return L""; @@ -771,7 +778,7 @@ public: if (!shouldCopy) return L""; - return DoCopySceneGraphObject(inInstances).second; + return DoCopySceneGraphObject(inInstances, preserveFileIds).second; } CFilePath CopyAction(Qt3DSDMActionHandle inAction, Qt3DSDMSlideHandle inSlide) override @@ -1064,6 +1071,18 @@ public: m_Bridge.GetOrCreateGraphRoot(retval); } + // Only one camera is active by default. If we already have one active, set the new camera + // to inactive. + if (inType == ComposerObjectTypes::Camera) { + auto cameraLayer = m_Bridge.GetResidingLayer(retval); + if (!m_Doc.getActiveCamera(cameraLayer).Valid()) { + m_Doc.setActiveCamera(cameraLayer, retval); + } else { + SetInstancePropertyValue( + retval, m_Bridge.GetSceneAsset().m_Eyeball.m_Property, false); + } + } + // if we did not set time range earlier, let's set it now to match parent TInstanceHandle handle = FinalizeAddOrDrop(retval, inParent, inInsertType, inPosition, !setTimeRange, selectCreatedInstance, false); @@ -1164,8 +1183,15 @@ public: if (!m_Bridge.GetMaterialFromImageInstance(instance, theParent, theProperty)) m_Bridge.GetLayerFromImageProbeInstance(instance, theParent, theProperty); - if (theParent.Valid()) - m_PropertySystem.SetInstancePropertyValue(theParent, theProperty, SLong4()); + if (theParent.Valid()) { + auto type = m_PropertySystem.GetAdditionalMetaDataType(theParent, theProperty); + if (type == AdditionalMetaDataType::Image) { + m_PropertySystem.SetInstancePropertyValue(theParent, theProperty, SLong4()); + } else if (type == AdditionalMetaDataType::Texture) { + m_PropertySystem.SetInstancePropertyValue(theParent, theProperty, + std::make_shared<CDataStr>(Q3DStudio::CString())); + } + } } else if (m_Bridge.IsBehaviorInstance(instance) || m_Bridge.IsEffectInstance(instance) || m_Bridge.IsCustomMaterialInstance(instance)) { // Check if this is the last instance that uses the same sourcepath property @@ -1421,6 +1447,24 @@ public: SetName(theMaterial, materialName); } + const dynamic::SPropertyDefinition *findDynamicProperty(const SMetaDataDynamicObject &dynObj, + CRegisteredString name) + { + for (int i = 0; i < dynObj.m_Properties.size(); i++) { + if (dynObj.m_Properties[i].m_Name == name) + return &dynObj.m_Properties[i]; + } + return nullptr; + } + + bool isDynamicObjectInstance(TInstanceHandle instance) const + { + return m_DataCore.IsInstanceOrDerivedFrom( + instance, m_Bridge.GetObjectDefinitions().m_CustomMaterial.m_Instance) + || m_DataCore.IsInstanceOrDerivedFrom( + instance, m_Bridge.GetObjectDefinitions().m_Effect.m_Instance); + } + // Normal way in to the system. void SetInstancePropertyValue(TInstanceHandle instance, TPropertyHandle propName, const SValue &value, bool inAutoDelete = true) override @@ -1429,25 +1473,64 @@ public: AdditionalMetaDataType::Value theProperytMetaData = thePropertySystem.GetAdditionalMetaDataType(instance, propName); TSlideHandle theNewSlide(GetSlideForProperty(instance, propName)); - if (theProperytMetaData == AdditionalMetaDataType::Image) { + if (theProperytMetaData == AdditionalMetaDataType::Image + || theProperytMetaData == AdditionalMetaDataType::Texture) { TDataStrPtr theImageSourcePath = get<TDataStrPtr>(value); bool hasValue = theImageSourcePath && theImageSourcePath->GetLength() > 0; qt3dsdm::Qt3DSDMInstanceHandle theImageInstance = GetImageInstanceForProperty(instance, propName); + SMetaDataDynamicObject *dynObj = nullptr; + if (isDynamicObjectInstance(instance)) { + TInstanceHandleList parents; + m_DataCore.GetInstanceParents(instance, parents); + if (parents.size() > 0) + dynObj = m_MetaData.GetDynamicObjectByInstance(parents[0]); + } if (hasValue) { - if (theImageInstance.Valid() == false) + bool imageInstanceCreated = false; + if (theImageInstance.Valid() == false) { theImageInstance = CreateImageInstanceForMaterialOrLayer(instance, propName); + imageInstanceCreated = true; + } if (theImageInstance) { SetInstancePropertyValue(theImageInstance, m_Bridge.GetSourcePathProperty(), value, inAutoDelete); + SetInstancePropertyValue(theImageInstance, m_Bridge.GetNameProperty(), + std::make_shared<CDataStr>( + Q3DStudio::CString(thePropertySystem + .GetName(propName).wide_str()))); + if (dynObj && (g_StudioApp.IsConvertingPresentationOn() + || imageInstanceCreated)) { + // In this case we are just loading the presentation and need to convert old-style + // texture paths into images. + // Set the image defaults from the dynamic object + const dynamic::SPropertyDefinition *dynamicProperty + = findDynamicProperty(*dynObj, m_StringTable.GetRenderStringTable() + .RegisterStr(thePropertySystem.GetName(propName).c_str())); + m_PropertySystem.SetInstancePropertyValue(theImageInstance, + m_Bridge.GetObjectDefinitions().m_Image.m_MinFilter, + std::make_shared<CDataStr>( + Q3DStudio::CString(MapEnum(dynamicProperty->m_MinFilterOp)))); + m_PropertySystem.SetInstancePropertyValue(theImageInstance, + m_Bridge.GetObjectDefinitions().m_Image.m_MagFilter, + std::make_shared<CDataStr>( + Q3DStudio::CString(MapEnum(dynamicProperty->m_MagFilterOp)))); + m_PropertySystem.SetInstancePropertyValue(theImageInstance, + m_Bridge.GetObjectDefinitions().m_Image.m_TilingU, + std::make_shared<CDataStr>( + Q3DStudio::CString(MapEnum(dynamicProperty->m_CoordOp)))); + m_PropertySystem.SetInstancePropertyValue(theImageInstance, + m_Bridge.GetObjectDefinitions().m_Image.m_TilingV, + std::make_shared<CDataStr>( + Q3DStudio::CString(MapEnum(dynamicProperty->m_CoordOp)))); + } // Clear subpresentation value SetInstancePropertyValue(theImageInstance, m_Bridge.GetSceneImage().m_SubPresentation, std::make_shared<CDataStr>(Q3DStudio::CString()), inAutoDelete); } - } else { if (theImageInstance.Valid()) { TSlideHandle theInstanceSlide = GetAssociatedSlide(instance); @@ -1511,7 +1594,7 @@ public: m_AssetGraph.GetParent(instance), instance, theNewSlide, docDir, log, std::bind(CPerformImport::ImportToComposerFromImportFile, std::placeholders::_1, std::placeholders::_2), - DocumentEditorInsertType::Unknown, CPt(), times.first); + DocumentEditorInsertType::Unknown, CPt(), times.first, false); } thePropertySystem.SetInstancePropertyValue(instance, propName, value); } else if (propName == m_Bridge.GetObjectDefinitions().m_Path.m_PathType @@ -1571,6 +1654,20 @@ public: } // Now set the property for reals thePropertySystem.SetInstancePropertyValue(instance, propName, value); + } else if (propName == m_Bridge.GetSceneAsset().m_Eyeball + && m_Bridge.IsCameraInstance(instance)) { + auto cameraLayer = m_Bridge.GetResidingLayer(instance); + auto activeCamera = m_Doc.getActiveCamera(cameraLayer); + if ((instance != activeCamera) && get<bool>(value)) { + // Only one camera per layer should be active. Set the previous one to inactive if + // we are activating another one. + if (activeCamera.Valid()) + thePropertySystem.SetInstancePropertyValue(activeCamera, propName, false); + m_Doc.setActiveCamera(cameraLayer, instance); + } else if (!get<bool>(value) && activeCamera == instance) { + m_Doc.setActiveCamera(cameraLayer, {}); // Inactivating current active camera. + } + thePropertySystem.SetInstancePropertyValue(instance, propName, value); } else { if (propName != m_Bridge.GetAlias().m_ReferencedNode.m_Property) { thePropertySystem.SetInstancePropertyValue(instance, propName, value); @@ -1852,6 +1949,7 @@ public: // Keep material names the same so that if you change the material type // any relative path links will still work. // Next bug is harder (keep id's the same). + Q3DStudio::CString fileId = GetFileId(instance); Q3DStudio::CString theName = GetName(instance); SLong4 theGuid = m_Bridge.GetInstanceGUID(instance); TInstanceHandle nextChild = m_AssetGraph.GetSibling(instance, true); @@ -1911,6 +2009,9 @@ public: m_Bridge.GetObjectDefinitions().m_Lightmaps.m_LightmapShadow, theLightmapShadowValue, false); + m_DataCore.SetInstancePropertyValue(newMaterial, + m_Bridge.GetObjectDefinitions().m_Asset.m_FileId, + std::make_shared<CDataStr>(fileId.c_str())); SetName(newMaterial, theName, false); m_Bridge.SetInstanceGUID(newMaterial, theGuid); // Copy all actions from old material instance to new material instance @@ -2031,7 +2132,7 @@ public: && name != QLatin1String("timebartext"); } - void saveIfMaterial(Qt3DSDMInstanceHandle instance) + void saveIfMaterial(Qt3DSDMInstanceHandle instance) override { Qt3DSDMInstanceHandle material; if (m_Bridge.isInsideMaterialContainer(instance)) { @@ -2123,7 +2224,8 @@ public: } const QFileInfo fileInfo(file); - writeProperty(file, QStringLiteral("path"), fileInfo.absoluteFilePath()); + writeProperty(file, QStringLiteral("path"), + projDir.relativeFilePath(fileInfo.absoluteFilePath())); QMapIterator<QString, Qt3DSDMInstanceHandle> i(textureHandles); while (i.hasNext()) { @@ -2496,6 +2598,16 @@ public: void copyMaterialProperties(Qt3DSDMInstanceHandle src, Qt3DSDMInstanceHandle dst) override { + const EStudioObjectType matType = m_Bridge.GetObjectType(src); + QString materialTypeString; + if (matType == OBJTYPE_CUSTOMMATERIAL) + materialTypeString = m_Bridge.GetSourcePath(src); + else if (matType == OBJTYPE_MATERIAL) + materialTypeString = QStringLiteral("Standard Material"); + else + return; + SetMaterialType(dst, materialTypeString); + const auto srcSlide = m_SlideSystem.GetApplicableSlide(src); const auto dstSlide = m_SlideSystem.GetApplicableSlide(dst); const auto name = GetName(dst); @@ -2542,8 +2654,7 @@ public: TSlideHandle inDestSlide, TInstanceHandle inDestInstance) { m_SlideCore.CopyProperties(inSourceSlide, inSourceInstance, inDestSlide, inDestInstance); - m_AnimationCore.CopyAnimations(inSourceSlide, inSourceInstance, inDestSlide, - inDestInstance); + m_animCore.CopyAnimations(inSourceSlide, inSourceInstance, inDestSlide, inDestInstance); } void UnlinkProperty(TInstanceHandle instance, TPropertyHandle propName) override @@ -2726,7 +2837,7 @@ public: } SetTimeRange(inInstance, theTimeRange.first + inOffset, theTimeRange.second + inOffset); // Offset all the keyframes linked to animations of this instance by this offset. - m_AnimationCore.OffsetAnimations(m_Doc.GetActiveSlide(), inInstance, inOffset); + m_animCore.OffsetAnimations(m_Doc.GetActiveSlide(), inInstance, inOffset); // Offset children time as well CGraphIterator theChildren; @@ -2809,8 +2920,8 @@ public: } template <typename TKeyframeType> - void AddKeyframes(Qt3DSDMAnimationHandle animHandle, const float *keyframeValues, long numValues, - long inOffsetInSeconds) + void AddKeyframes(Qt3DSDMAnimationHandle animHandle, const float *keyframeValues, + long numValues, long timeOffset) { long numFloatsPerKeyframe = sizeof(TKeyframeType) / sizeof(float); if (numValues % numFloatsPerKeyframe) { @@ -2820,27 +2931,74 @@ public: long numKeyframes = numValues / numFloatsPerKeyframe; for (long idx = 0; idx < numKeyframes; ++idx) { TKeyframeType theData(keyframes[idx]); - theData.m_KeyframeSeconds += inOffsetInSeconds; - m_AnimationCore.InsertKeyframe(animHandle, theData); + theData.m_time += timeOffset; + m_animCore.InsertKeyframe(animHandle, theData); } } - void SetKeyframeTime(TKeyframeHandle inKeyframe, long inTime) override + void SetKeyframeTime(TKeyframeHandle kfHandle, long time) override { - float theTimeinSecs = static_cast<float>(inTime) / 1000.f; - // round off to 4 decimal place to workaround precision issues - // TODO: fix this, either all talk float OR long. choose one. - theTimeinSecs = ceilf(theTimeinSecs * 10000.0f) / 10000.0f; - TKeyframe theData = m_AnimationCore.GetKeyframeData(inKeyframe); - // Function programming paradigm, returns new value instead of changing - // current value. - theData = qt3dsdm::SetKeyframeSeconds(theData, theTimeinSecs); - m_AnimationCore.SetKeyframeData(inKeyframe, theData); + TKeyframe kfData = m_animCore.GetKeyframeData(kfHandle); + + // offset control points for bezier keyframes + offsetBezier(kfData, time - getKeyframeTime(kfData)); + + // Functional programming paradigm, returns new value instead of changing current value. + kfData = qt3dsdm::setKeyframeTime(kfData, time); + m_animCore.SetKeyframeData(kfHandle, kfData); + + // For bezier keyframes check that control points of the moved keyframe and the keyframes + // before and after it don't go beyond its adjacent keyframes times. + Qt3DSDMAnimationHandle anim = m_animCore.GetAnimationForKeyframe(kfHandle); + EAnimationType animType = m_animCore.GetAnimationInfo(anim).m_AnimationType; + if (animType == EAnimationTypeBezier) { + TKeyframeHandleList keyframes; + m_animCore.GetKeyframes(anim, keyframes); + for (size_t i = 0; i < keyframes.size(); ++i) { + if (keyframes[i] == kfHandle) { + SBezierKeyframe kfCurr = get<SBezierKeyframe>(m_animCore.GetKeyframeData( + kfHandle)); + if (i > 0) { // check overlap with prev keyframe + SBezierKeyframe kfPrev = get<SBezierKeyframe>(m_animCore.GetKeyframeData( + keyframes[i - 1])); + if (kfPrev.m_OutTangentTime > kfCurr.m_time) + kfPrev.m_OutTangentTime = kfCurr.m_time; + + if (kfCurr.m_InTangentTime < kfPrev.m_time) + kfCurr.m_InTangentTime = kfPrev.m_time; + + m_animCore.SetKeyframeData(keyframes[i - 1], kfPrev); + + // Mahmoud_TODO: trim the value proportinally also so that the control + // point lines maintains the same slope after the time is trimmed + } + + if (i < keyframes.size() - 1) { // check overlap with next keyframe + SBezierKeyframe kfNext = get<SBezierKeyframe>(m_animCore.GetKeyframeData( + keyframes[i + 1])); + if (kfNext.m_InTangentTime < kfCurr.m_time) + kfNext.m_InTangentTime = kfCurr.m_time; + + if (kfCurr.m_OutTangentTime > kfNext.m_time) + kfCurr.m_OutTangentTime = kfNext.m_time; + + m_animCore.SetKeyframeData(keyframes[i + 1], kfNext); + } + m_animCore.SetKeyframeData(kfHandle, kfCurr); + break; + } + } + } + } + + void setBezierKeyframeValue(TKeyframeHandle kfHandle, const TKeyframe &kfData) override + { + m_animCore.SetKeyframeData(kfHandle, kfData); } void DeleteAllKeyframes(Qt3DSDMAnimationHandle inAnimation) override { - m_AnimationCore.DeleteAllKeyframes(inAnimation); + m_animCore.DeleteAllKeyframes(inAnimation); } void KeyframeProperty(Qt3DSDMInstanceHandle inInstance, Qt3DSDMPropertyHandle inProperty, @@ -2854,52 +3012,48 @@ public: const wchar_t *propName, long subIndex, EAnimationType animType, const float *keyframeValues, long numValues, bool /*inUserEdited*/) override { - Qt3DSDMPropertyHandle propHdl = - m_DataCore.GetAggregateInstancePropertyByName(instance, propName); - if (propHdl.Valid() == false) { + Qt3DSDMPropertyHandle property = m_DataCore.GetAggregateInstancePropertyByName(instance, + propName); + if (!property.Valid()) { QT3DS_ASSERT(false); return 0; } - if (inSlide.Valid() == false) { + if (!inSlide.Valid()) { Qt3DSDMSlideHandle theSlide = m_SlideSystem.GetAssociatedSlide(instance); - if (theSlide.Valid() == false) { + if (!theSlide.Valid()) { assert(0); return 0; } - if (m_SlideSystem.IsPropertyLinked(instance, propHdl)) + if (m_SlideSystem.IsPropertyLinked(instance, property)) theSlide = m_SlideSystem.GetMasterSlide(theSlide); inSlide = theSlide; } Qt3DSDMAnimationHandle animHandle = - m_AnimationCore.GetAnimation(inSlide, instance, propHdl, subIndex); + m_animCore.GetAnimation(inSlide, instance, property, subIndex); - if (animHandle.Valid() == true) - m_AnimationCore.DeleteAnimation(animHandle); + if (animHandle.Valid()) + m_animCore.DeleteAnimation(animHandle); animHandle = - m_AnimationCore.CreateAnimation(inSlide, instance, propHdl, subIndex, animType, false); + m_animCore.CreateAnimation(inSlide, instance, property, subIndex, animType, false); long theStartTime = GetTimeRange(instance).first; - long theTimeOffsetInSeconds = long(theStartTime / 1000.f); switch (animType) { case EAnimationTypeLinear: - AddKeyframes<SLinearKeyframe>(animHandle, keyframeValues, numValues, - theTimeOffsetInSeconds); + AddKeyframes<SLinearKeyframe>(animHandle, keyframeValues, numValues, theStartTime); break; case EAnimationTypeBezier: - AddKeyframes<SBezierKeyframe>(animHandle, keyframeValues, numValues, - theTimeOffsetInSeconds); + AddKeyframes<SBezierKeyframe>(animHandle, keyframeValues, numValues, theStartTime); break; case EAnimationTypeEaseInOut: AddKeyframes<SEaseInEaseOutKeyframe>(animHandle, keyframeValues, numValues, - theTimeOffsetInSeconds); + theStartTime); break; default: QT3DS_ASSERT(false); - AddKeyframes<SLinearKeyframe>(animHandle, keyframeValues, numValues, - theTimeOffsetInSeconds); + AddKeyframes<SLinearKeyframe>(animHandle, keyframeValues, numValues, theStartTime); break; } return animHandle; @@ -2914,9 +3068,9 @@ public: return false; } Qt3DSDMAnimationHandle animHandle = - m_AnimationCore.GetAnimation(inSlide, instance, propHdl, subIndex); + m_animCore.GetAnimation(inSlide, instance, propHdl, subIndex); if (animHandle.Valid()) { - m_AnimationCore.DeleteAnimation(animHandle); + m_animCore.DeleteAnimation(animHandle); return true; } return false; @@ -2924,7 +3078,7 @@ public: void SetIsArtistEdited(Qt3DSDMAnimationHandle inAnimation, bool inEdited = true) override { - m_AnimationCore.SetIsArtistEdited(inAnimation, inEdited); + m_animCore.SetIsArtistEdited(inAnimation, inEdited); } qt3dsdm::Qt3DSDMInstanceHandle @@ -3000,11 +3154,13 @@ public: bool inGenerateUniqueName, DocumentEditorInsertType::Enum inInsertType, const CPt &inPosition, + bool preserveFileIds, bool notifyRename = true) { std::shared_ptr<IComposerSerializer> theSerializer = m_Doc.CreateSerializer(); TInstanceHandleList retval = theSerializer->SerializeSceneGraphObject( - *inReader, m_Doc.GetDocumentDirectory(), inNewRoot, GetActiveSlide(inNewRoot)); + *inReader, m_Doc.GetDocumentDirectory(), inNewRoot, GetActiveSlide(inNewRoot), + preserveFileIds); for (size_t idx = 0, end = retval.size(); idx < end; ++idx) { qt3dsdm::Qt3DSDMInstanceHandle theInstance(retval[idx]); if (inInsertType == DocumentEditorInsertType::NextSibling) @@ -3023,7 +3179,8 @@ public: TInstanceHandle inNewRoot, bool inGenerateUniqueName, DocumentEditorInsertType::Enum inInsertType, - const CPt &inPosition) override + const CPt &inPosition, + bool preserveFileIds) override { qt3ds::QT3DSI32 theVersion = 0; std::shared_ptr<IDOMReader> theReader = m_Doc.CreateDOMReader( @@ -3031,13 +3188,14 @@ public: if (!theReader) return TInstanceHandleList(); return DoPasteSceneGraphObject(theReader, inNewRoot, inGenerateUniqueName, inInsertType, - inPosition, false); + inPosition, preserveFileIds, false); } virtual TInstanceHandleList PasteSceneGraphObjectMaster(const CFilePath &inFilePath, TInstanceHandle inNewRoot, bool inGenerateUniqueName, - DocumentEditorInsertType::Enum inInsertType, const CPt &inPosition) override + DocumentEditorInsertType::Enum inInsertType, const CPt &inPosition, + bool preserveFileIds) override { qt3ds::QT3DSI32 theVersion = 0; std::shared_ptr<IDOMReader> theReader = m_Doc.CreateDOMReader( @@ -3048,7 +3206,8 @@ public: std::shared_ptr<IComposerSerializer> theSerializer = m_Doc.CreateSerializer(); TInstanceHandleList retval = theSerializer->SerializeSceneGraphObject( *theReader, m_Doc.GetDocumentDirectory(), inNewRoot, - m_Doc.GetStudioSystem()->GetSlideSystem()->GetMasterSlide(GetActiveSlide(inNewRoot))); + m_Doc.GetStudioSystem()->GetSlideSystem()->GetMasterSlide(GetActiveSlide(inNewRoot)), + preserveFileIds); for (size_t idx = 0, end = retval.size(); idx < end; ++idx) { qt3dsdm::Qt3DSDMInstanceHandle theInstance(retval[idx]); if (inInsertType == DocumentEditorInsertType::NextSibling) @@ -3253,7 +3412,7 @@ public: // Paste into the master slide of the new component TInstanceHandleList insertedHandles = theSerializer->SerializeSceneGraphObject( *theReader,m_Doc.GetDocumentDirectory(), component, - m_SlideSystem.GetMasterSlide(theComponentSlide)); + m_SlideSystem.GetMasterSlide(theComponentSlide), true); // Restore the original time range for all objects. if (insertedHandles.size()) { @@ -3278,19 +3437,10 @@ public: if (oldType == "ReferencedMaterial") { Qt3DSDMInstanceHandle refMaterial = m_Bridge.getMaterialReference(instance); - if (refMaterial.Valid()) { - const Q3DStudio::CString refType = GetObjectTypeName(refMaterial); - QString v; - if (refType == "CustomMaterial") - v = m_Bridge.GetSourcePath(refMaterial); - else - v = QStringLiteral("Standard Material"); - - SetMaterialType(instance, v); + if (refMaterial.Valid()) copyMaterialProperties(refMaterial, instance); - } else { + else SetMaterialType(instance, QStringLiteral("Standard Material")); - } const auto name = GetName(instance); if (!name.toQString().endsWith(QLatin1String("_animatable"))) @@ -3336,7 +3486,7 @@ public: theSerializer->SerializeSceneGraphObject( *theReader, m_Doc.GetDocumentDirectory(), targetComponent, - m_SlideSystem.GetMasterSlide(theComponentSlide)); + m_SlideSystem.GetMasterSlide(theComponentSlide), true); if (insertedHandles.size()) { // Restore the original time range for all objects. @@ -3381,7 +3531,7 @@ public: { qt3dsdm::TInstanceHandleList theInstances(ToGraphOrdering(inInstances)); std::shared_ptr<IDOMReader> theReader(CopySceneGraphObjectsToMemory(theInstances)); - return DoPasteSceneGraphObject(theReader, inDest, true, inInsertType, CPt(), false); + return DoPasteSceneGraphObject(theReader, inDest, true, inInsertType, CPt(), false, false); } Qt3DSDMActionHandle AddAction(Qt3DSDMSlideHandle inSlide, Qt3DSDMInstanceHandle inOwner, @@ -3515,6 +3665,8 @@ public: int newSlideIndex = m_SlideSystem.GetSlideIndex(theNewSlide); m_SlideSystem.SetActiveSlide(inMasterSlide, newSlideIndex); m_Doc.NotifyActiveSlideChanged(theNewSlide, true); + // Make sure layer is reseted + m_Doc.SetActiveLayer(0); CheckSlideGroupPlayThroughTo(theNewSlide); Qt3DSDMInstanceHandle theInstance = m_Doc.GetSelectedInstance(); if (theInstance.Valid() && GetAssociatedSlide(theInstance) != inMasterSlide) @@ -3578,6 +3730,18 @@ public: m_Bridge.GetObjectDefinitions().m_Named.m_NameProp, std::make_shared<CDataStr>(theNewName.c_str())); + // Change non-masterslide instance names to unique. + TInstanceHandleList slideInstances; + m_SlideSystem.GetAssociatedInstances(theNewSlide, slideInstances); + for (size_t idx = 0, end = slideInstances.size(); idx < end; ++idx) { + TInstanceHandle theInstance(slideInstances[idx]); + if (m_SlideSystem.GetApplicableSlide(theInstance) + != m_SlideSystem.GetMasterSlide(theInstance) + && !m_Bridge.GetName(theInstance).IsEmpty()) { + SetName(theInstance, m_Bridge.GetName(theInstance), true); + } + } + // Ensure the active slide change gets recorded in the transaction system so that // undo will place us back at the old slide before things start reading from the object // model. @@ -3586,6 +3750,8 @@ public: m_Doc.SetActiveSlideWithTransaction(theNewSlide); m_Doc.NotifyActiveSlideChanged(theNewSlide, true); + // Make sure layer is reseted + m_Doc.SetActiveLayer(0); CheckSlideGroupPlayThroughTo(theNewSlide); return theNewSlide; } @@ -3718,7 +3884,8 @@ public: Qt3DSDMInstanceHandle inRoot, Qt3DSDMSlideHandle inSlide, Q3DStudio::CString inDocDir, STranslationLog &inTranslationLog, function<SImportResult(IComposerEditorInterface &, Q3DStudio::CString)> inImportFunction, - DocumentEditorInsertType::Enum inInsertType, const CPt &inPosition, long inStartTime) + DocumentEditorInsertType::Enum inInsertType, const CPt &inPosition, long inStartTime, + bool selectAfterImport) { CFilePath outputDir(inImportFilePath.GetDirectory()); bool alwaysKeepDirectory = outputDir.Exists(); @@ -3761,7 +3928,7 @@ public: // Do not check for unique name as we set it anyway after getting new handle Qt3DSDMInstanceHandle retval = FinalizeAddOrDrop(importToComposer->GetRoot(), inParent, inInsertType, - inPosition, inStartTime == -1, true, false); + inPosition, inStartTime == -1, selectAfterImport, false); SetName(retval, theRelPath.GetFileStem(), true); updateMaterialFiles(); @@ -3821,7 +3988,7 @@ public: inParent, 0, inSlide, docDir, translator.m_TranslationLog, std::bind(CPerformImport::ImportToComposer, translator, std::placeholders::_1, std::placeholders::_2), inDropType, - inPosition, inStartTime); + inPosition, inStartTime, true); if (retval.Valid()) { CFilePath theRelativeImport = m_Doc.GetRelativePathToDoc(outputFileName); m_ImportFileToDAEMap.insert( @@ -3844,7 +4011,7 @@ public: return DoImport(inFullPathToDocument, inFullPathToDocument, inParent, 0, inSlide, docDir, log, std::bind(CPerformImport::ImportToComposerFromImportFile, std::placeholders::_1, std::placeholders::_2), - inDropType, inPosition, inStartTime); + inDropType, inPosition, inStartTime, true); } QString findUniqueMaterialName(const QString &name, const QString &importPath) @@ -4009,18 +4176,6 @@ public: inStartTime == -1); } - static void *l_alloc(void *ud, void *ptr, size_t osize, size_t nsize) - { - Q_UNUSED(ud) - Q_UNUSED(osize) - - if (nsize == 0) { - free(ptr); - return nullptr; - } else - return realloc(ptr, nsize); - } - QString LoadScriptFile(const CFilePath &inFile) { QString retval; @@ -4097,12 +4252,25 @@ public: theHandler->DisplayImportFailed(inSrcPath, resultDialogStr, true); } + template <typename T> + const wchar_t *MapEnum(T enumValue) { + SEnumNameMap *map = SEnumParseMap<T>::GetMap(); + while (map->m_Enum != -1) { + if (map->m_Enum == enumValue) + return map->m_WideName; + map = map + 1; + } + return nullptr; + } + // Apply meta data to a new dynamic instance. This sets up the default properties to // be what the meta data specifies. void ApplyDynamicMetaData(Qt3DSDMInstanceHandle inDynamicInstance, - Qt3DSDMInstanceHandle inDynamic) + Qt3DSDMInstanceHandle inDynamic, + const SMetaDataDynamicObject &dynObj) { std::vector<SMetaDataLoadWarning> theWarnings; + // For all of the object std::ref properties, check if they have an absolute path // reference (path starts with "Scene". If they do, then attempt to resolve the reference. vector<Qt3DSDMMetaDataPropertyHandle> theProperties; @@ -4172,6 +4340,62 @@ public: m_DataCore.SetInstancePropertyValue(inDynamic, theInfo.m_Property, theRef); } } + } else if (theInfo.m_CompleteType == CompleteMetaDataType::Texture + && GetValueType(theInfo.m_DefaultValue) == DataModelDataType::String) { + SValue value; + m_DataCore.GetInstancePropertyValue(inDynamic, theInfo.m_Property, value); + // Set default value to the instance + if (!value.empty()) { + TDataStrPtr theImageSourcePath = get<TDataStrPtr>(value); + bool hasValue = theImageSourcePath && theImageSourcePath->GetLength() > 0; + qt3dsdm::Qt3DSDMInstanceHandle theImageInstance = + GetImageInstanceForProperty(inDynamicInstance, theInfo.m_Property); + const dynamic::SPropertyDefinition *dynamicProperty + = findDynamicProperty(dynObj, m_StringTable.GetRenderStringTable(). + RegisterStr(theInfo.m_Name.wide_str())); + if (hasValue || (dynamicProperty && dynamicProperty->m_ImagePath.IsValid())) { + if (!theImageInstance.Valid()) { + theImageInstance = CreateImageInstanceForMaterialOrLayer( + inDynamicInstance, theInfo.m_Property); + if (dynamicProperty) { + m_PropertySystem.SetInstancePropertyValue(theImageInstance, + m_Bridge.GetObjectDefinitions().m_Image.m_MinFilter, + std::make_shared<CDataStr>( + Q3DStudio::CString(MapEnum(dynamicProperty->m_MinFilterOp)))); + m_PropertySystem.SetInstancePropertyValue(theImageInstance, + m_Bridge.GetObjectDefinitions().m_Image.m_MagFilter, + std::make_shared<CDataStr>( + Q3DStudio::CString(MapEnum(dynamicProperty->m_MagFilterOp)))); + m_PropertySystem.SetInstancePropertyValue(theImageInstance, + m_Bridge.GetObjectDefinitions().m_Image.m_TilingU, + std::make_shared<CDataStr>( + Q3DStudio::CString(MapEnum(dynamicProperty->m_CoordOp)))); + m_PropertySystem.SetInstancePropertyValue(theImageInstance, + m_Bridge.GetObjectDefinitions().m_Image.m_TilingV, + std::make_shared<CDataStr>( + Q3DStudio::CString(MapEnum(dynamicProperty->m_CoordOp)))); + if (!hasValue) { + value = std::make_shared<CDataStr>( + Q3DStudio::CString(dynamicProperty->m_ImagePath.c_str())); + } + } + } + if (theImageInstance) { + SetInstancePropertyValue(theImageInstance, m_Bridge.GetNameProperty(), + std::make_shared<CDataStr>(Q3DStudio::CString( + m_PropertySystem.GetName(theInfo.m_Property).wide_str()))); + SetInstancePropertyValue(theImageInstance, + m_Bridge.GetSourcePathProperty(), value); + // Clear subpresentation value + SetInstancePropertyValue(theImageInstance, + m_Bridge.GetSceneImage().m_SubPresentation, + make_shared<CDataStr>(Q3DStudio::CString())); + } + } else { + m_DataCore.SetInstancePropertyValue(inDynamicInstance, theInfo.m_Property, + make_shared<CDataStr>(Q3DStudio::CString())); + } + } } } } @@ -4239,11 +4463,12 @@ public: } } if (theParentInstance.Valid()) { + SMetaDataDynamicObject dynObj; TInstanceHandle retval(IDocumentEditor::CreateSceneGraphInstance( theParentInstance, inParent, inSlide, m_DataCore, m_SlideSystem, m_Bridge.GetObjectDefinitions(), m_AssetGraph, m_MetaData)); - ApplyDynamicMetaData(retval, theParentInstance); + ApplyDynamicMetaData(retval, theParentInstance, dynObj); if (inStartTime != -1) SetStartTime(retval, inStartTime); @@ -4438,7 +4663,6 @@ public: if (theRelativePath.toCString() == GetSourcePath(existing[idx])) theParentInstance = existing[idx]; } - if (theParentInstance.Valid() == false) { if (theShaderFile.Exists()) { theParentInstance = m_DataCore.CreateInstance(); @@ -4463,18 +4687,31 @@ public: IDocumentEditor::fixDefaultTexturePaths(theParentInstance); DisplayLoadWarnings(shaderFile, theWarnings, QString()); } else { - if (theHandler) + if (theHandler) { theHandler->DisplayImportFailed(theShaderFile.toQString(), QObject::tr("Unable to load Shader File"), false); + } return 0; } } + const SMetaDataDynamicObject *dynObj; + dynObj = m_MetaData.GetDynamicObjectByInstance(theParentInstance); + if (!dynObj) { + if (theHandler) { + theHandler->DisplayImportFailed(theShaderFile.toQString(), + QObject::tr("Unable to load Shader File"), + false); + } + return 0; + } TInstanceHandle retval(IDocumentEditor::CreateSceneGraphInstance( theParentInstance, inParent, inSlide, m_DataCore, m_SlideSystem, m_Bridge.GetObjectDefinitions(), m_AssetGraph, m_MetaData, inTargetId)); + ApplyDynamicMetaData(retval, theParentInstance, *dynObj); + if (inStartTime != -1) SetStartTime(retval, inStartTime); @@ -4602,10 +4839,13 @@ public: // Precondition is that our source path to instance map // has all of the source-path-to-instance hooks already looked up. - void DoRefreshImport(const CFilePath &inOldFile, const CFilePath &inNewFile) + void DoRefreshImport(const CFilePath &inOldFile, const CFilePath &inNewFile, + const CFilePath &importFilePath) { ScopedBoolean __ignoredDirs(m_IgnoreDirChange); vector<CFilePath> importFileList; + if (importFilePath.Exists() && importFilePath.IsFile()) + importFileList.push_back(importFilePath.filePath()); // Find which import files use this dae file. for (TCharPtrToSlideInstanceMap::iterator theIter = m_SourcePathInstanceMap.begin(), @@ -4639,75 +4879,73 @@ public: // OK, for each import file // 1. Find each group in the system using that import file as its source path. // 2. for each group we find, build a map of import id->item that we will use to - // communicate the import changes to the item. - // 4. Run the refresh process using a composer editor that runs off of our - // mappings + // communicate the import changes to the item. + // 4. Run the refresh process using a composer editor that runs off of our mappings TIdMultiMap theGroupIdMap; for (size_t importIdx = 0, end = importFileList.size(); importIdx < end; ++importIdx) { theGroupIdMap.clear(); CFilePath theImportFilePath = importFileList[importIdx]; CFilePath theImportRelativePath = m_Doc.GetRelativePathToDoc(theImportFilePath); TCharPtrToSlideInstanceMap::iterator theIter = - m_SourcePathInstanceMap.find(m_StringTable.RegisterStr(theImportRelativePath.toCString())); - if (theIter == m_SourcePathInstanceMap.end()) - continue; - // First pass just build the group id entries. This avoids us copying hashtables which - // may - // be quite expensive - for (TSlideInstanceList::iterator theSlideInst = theIter->second.begin(), - theSlideInstEnd = theIter->second.end(); - theSlideInst != theSlideInstEnd; ++theSlideInst) { - TInstanceHandle theRoot = theSlideInst->second; - TSlideHandle theSlide = theSlideInst->first; - - // For a depth first search of all children of this object *in this slide*, - // if they have an import id then add them to the map. - DepthFirstAddImportChildren(theSlide, theRoot, theGroupIdMap, theAddedInstances); - TIdMultiMap::iterator theGroupId = - theGroupIdMap - .insert(make_pair(m_StringTable.GetWideStr(GetImportId(theRoot)), - vector<pair<Qt3DSDMSlideHandle, Qt3DSDMInstanceHandle>>())) - .first; - insert_unique(theGroupId->second, make_pair(theSlide, theRoot)); - theAddedInstances.insert(theRoot); - } - // Since some objects may be completely free standing, we need to go through *all* - // objects. - // Unfortunately the first revision of the system didn't put import paths on objects so - // we need both the above loop *and* to consider every object who's import path matches - // out import document's relative path. - theIter = theImportPaths.find(m_StringTable.RegisterStr(theImportRelativePath.toCString())); - TSlideHandleList theAssociatedSlides; - if (theIter != theImportPaths.end()) { - vector<pair<Qt3DSDMSlideHandle, Qt3DSDMInstanceHandle>> &theInstances = - theIter->second; - for (size_t freeInstanceIdx = 0, end = theInstances.size(); freeInstanceIdx < end; - ++freeInstanceIdx) { - if (theAddedInstances.find(theInstances[freeInstanceIdx].second) - != theAddedInstances.end()) - continue; - theAssociatedSlides.clear(); - Qt3DSDMInstanceHandle theInstance(theInstances[freeInstanceIdx].second); - GetAllAssociatedSlides(theInstance, theAssociatedSlides); - TIdMultiMap::iterator theInstanceId = - theGroupIdMap - .insert( - make_pair(m_StringTable.GetWideStr(GetImportId(theInstance)), - vector<pair<Qt3DSDMSlideHandle, Qt3DSDMInstanceHandle>>())) - .first; - for (size_t slideIdx = 0, slideEnd = theAssociatedSlides.size(); - slideIdx < slideEnd; ++slideIdx) - insert_unique(theInstanceId->second, - make_pair(theAssociatedSlides[slideIdx], theInstance)); - theAddedInstances.insert(theInstance); + m_SourcePathInstanceMap.find(m_StringTable.RegisterStr(theImportRelativePath + .toCString())); + if (theIter != m_SourcePathInstanceMap.end()) { + // First pass just build the group id entries. This avoids us copying hashtables + // which may be quite expensive + for (TSlideInstanceList::iterator theSlideInst = theIter->second.begin(), + theSlideInstEnd = theIter->second.end(); + theSlideInst != theSlideInstEnd; ++theSlideInst) { + TInstanceHandle theRoot = theSlideInst->second; + TSlideHandle theSlide = theSlideInst->first; + + // For a depth first search of all children of this object *in this slide*, + // if they have an import id then add them to the map. + DepthFirstAddImportChildren(theSlide, theRoot, theGroupIdMap, + theAddedInstances); + TIdMultiMap::iterator theGroupId + = theGroupIdMap.insert({m_StringTable.GetWideStr(GetImportId(theRoot)), + {}}).first; + insert_unique(theGroupId->second, make_pair(theSlide, theRoot)); + theAddedInstances.insert(theRoot); + } + // Since some objects may be completely free standing, we need to go through *all* + // objects. + // Unfortunately the first revision of the system didn't put import paths on objects + // so we need both the above loop *and* to consider every object who's import path + // matches out import document's relative path. + theIter = theImportPaths.find(m_StringTable.RegisterStr(theImportRelativePath + .toCString())); + TSlideHandleList theAssociatedSlides; + if (theIter != theImportPaths.end()) { + vector<pair<Qt3DSDMSlideHandle, Qt3DSDMInstanceHandle>> &theInstances + = theIter->second; + for (size_t i = 0, end = theInstances.size(); i < end; ++i) { + if (theAddedInstances.find(theInstances[i].second) + != theAddedInstances.end()) { + continue; + } + theAssociatedSlides.clear(); + Qt3DSDMInstanceHandle theInstance(theInstances[i].second); + GetAllAssociatedSlides(theInstance, theAssociatedSlides); + TIdMultiMap::iterator theInstanceId + = theGroupIdMap + .insert({m_StringTable.GetWideStr(GetImportId(theInstance)), + {}}).first; + for (size_t slideIdx = 0, slideEnd = theAssociatedSlides.size(); + slideIdx < slideEnd; ++slideIdx) { + insert_unique(theInstanceId->second, + make_pair(theAssociatedSlides[slideIdx], theInstance)); + } + theAddedInstances.insert(theInstance); + } } } - // // OK, we have distinct maps sorted on a per-slide basis for all trees of children // of this asset. We now need to attempt to run the refresh algorithm. - qt3dsimp::ImportPtrOrError theImportPtr = qt3dsimp::Import::Load(theImportFilePath.toCString()); + qt3dsimp::ImportPtrOrError theImportPtr + = qt3dsimp::Import::Load(theImportFilePath.toCString()); if (!theImportPtr.m_Value) { QT3DS_ASSERT(false); continue; @@ -4727,7 +4965,8 @@ public: Q3DStudio::CString::ENDOFSTRING, false) && oldExtension.Compare(CDialogs::GetWideDAEFileExtension(), Q3DStudio::CString::ENDOFSTRING, false)) { - SColladaTranslator *colladaTranslator = new SColladaTranslator(inNewFile.toQString()); + SColladaTranslator *colladaTranslator + = new SColladaTranslator(inNewFile.toQString()); translationLog = &(colladaTranslator->m_TranslationLog); translator = colladaTranslator; #ifdef QT_3DSTUDIO_FBX @@ -4763,18 +5002,21 @@ public: updateMaterialFiles(); } - void RefreshImport(const CFilePath &inOldFile, const CFilePath &inNewFile) override + void RefreshImport(const CFilePath &inOldFile, const CFilePath &inNewFile, + const CFilePath &importFilePath) override { CDispatch &theDispatch(*m_Doc.GetCore()->GetDispatch()); + theDispatch.FireOnProgressBegin( QObject::tr("Refreshing Import "), QFileInfo(inNewFile.toQString()).fileName()); ScopedBoolean __ignoredDirs(m_IgnoreDirChange); try { m_SourcePathInstanceMap.clear(); GetSourcePathToInstanceMap(m_SourcePathInstanceMap, true, false); - DoRefreshImport(inOldFile, inNewFile); + DoRefreshImport(inOldFile, inNewFile, importFilePath); } catch (...) { } + theDispatch.FireOnProgressEnd(); } @@ -5115,6 +5357,8 @@ public: if (selectedInstances.size() > 0) { bool boolValue = false; SValue value; + qt3dsdm::Qt3DSDMInstanceHandle firstFoundCamera; + qt3dsdm::Qt3DSDMInstanceHandle foundCameraLayer; for (size_t idx = 0, end = selectedInstances.size(); idx < end; ++idx) { qt3dsdm::Qt3DSDMInstanceHandle handle(selectedInstances[idx]); if (handle.Valid()) { @@ -5123,7 +5367,21 @@ public: propertySystem->GetInstancePropertyValue(handle, property, value); boolValue = !qt3dsdm::get<bool>(value); } - propertySystem->SetInstancePropertyValue(handle, property, boolValue); + // First found camera is the one that ends up being activated if there are + // several in selection, per-layer. Skip the rest if setting eyeball to true. + // It is ok to deactivate (hide) all cameras, though. + if (m_DataCore.IsInstanceOrDerivedFrom( + handle, m_Bridge.GetObjectDefinitions().m_Camera.m_Instance)) { + auto currCameraLayer = m_Bridge.GetResidingLayer(handle); + if ((!firstFoundCamera.Valid() || boolValue) + && !(foundCameraLayer == currCameraLayer)) { + firstFoundCamera = handle; + foundCameraLayer = currCameraLayer; + } else if (boolValue) { + continue; + } + } + SetInstancePropertyValue(handle, property, boolValue); } } } @@ -5215,23 +5473,27 @@ public: } m_SourcePathInstanceMap.clear(); - GetSourcePathToInstanceMap(m_SourcePathInstanceMap); + GetSourcePathToInstanceMap(m_SourcePathInstanceMap, false); TInstanceHandleList theParents; SComposerObjectDefinitions &theDefinitions(m_Bridge.GetObjectDefinitions()); + QSet<QString> imageLoadSet; + + g_StudioApp.getRenderer().MakeContextCurrent(); for (size_t fileIdx = 0, fileEnd = inList.size(); fileIdx < fileEnd; ++fileIdx) { const SFileModificationRecord &theRecord(inList[fileIdx]); - CString theExtension = theRecord.m_File.GetExtension(); - bool isImport = theExtension.Compare(L"import", CString::ENDOFSTRING, false); + QString theExtension = theRecord.m_File.GetExtension().toQString().toLower(); + bool isImport = theExtension == QLatin1String("import"); CFilePath theRelativePath(m_Doc.GetRelativePathToDoc(theRecord.m_File)); const wchar_t *theString( m_DataCore.GetStringTable().RegisterStr(theRelativePath.toCString())); - if ((theExtension.CompareNoCase(L"ttf") - || theExtension.CompareNoCase(L"otf")) // should use CDialogs::IsFontFileExtension + if (CDialogs::fontExtensions().contains(theExtension) && m_Doc.GetSceneGraph() && m_Doc.GetSceneGraph()->GetTextRenderer()) { m_Doc.GetSceneGraph()->GetTextRenderer()->ReloadFonts(); + if (m_Doc.GetSceneGraph()->GetDistanceFieldRenderer()) + m_Doc.GetSceneGraph()->GetDistanceFieldRenderer()->ReloadFonts(); CFilePath thePath = m_Doc.GetDocumentDirectory(); CFilePath theFontCache = CFilePath::CombineBaseAndRelative(thePath, L"fontcache"); theFontCache.DeleteThisDirectory(true); @@ -5286,9 +5548,9 @@ public: if (theInsertResult.second == false) theInsertResult.first->second = theDAERelativePath; } - } else if (theExtension.Compare(L"qml", CString::ENDOFSTRING, false) + } else if (CDialogs::behaviorExtensions().contains(theExtension) && theRecord.m_ModificationType != FileModificationType::Created - && theInstances.empty() == false) { + && !theInstances.empty()) { // First, refresh the parent behavior. if (!hasDispatchNotificationScope) { theDispatch.FireBeginDataModelNotifications(); @@ -5331,38 +5593,74 @@ public: } } } - } else if (theExtension.Compare(L"effect", CString::ENDOFSTRING, false) + } else if (CDialogs::effectExtensions().contains(theExtension) && theRecord.m_ModificationType != FileModificationType::Created - && theInstances.empty() == false) { - CString theNameStr = GetName(theInstances[0].second); + && !theInstances.empty()) { std::vector<SMetaDataLoadWarning> theWarnings; NVScopedRefCounted<qt3ds::render::IRefCountedInputStream> theStream( m_InputStreamFactory->GetStreamForFile(theRecord.m_File.toQString())); if (theStream) { - m_MetaData.LoadEffectInstance(m_StringTable.GetNarrowStr(theRelativePath.toCString()), + m_MetaData.LoadEffectInstance(m_StringTable.GetNarrowStr( + theRelativePath.toCString()), theInstances[0].second, - TCharStr(theNameStr), + theRelativePath.GetFileStem().c_str(), theWarnings, *theStream); IDocumentEditor::fixDefaultTexturePaths(theInstances[0].second); } + QList<qt3dsdm::Qt3DSDMInstanceHandle> insts; for (size_t i = 0; i < theInstances.size(); ++i) { theDispatch.FireReloadEffectInstance(theInstances[i].second); - theDispatch.FireImmediateRefreshInstance(theInstances[i].second); + insts.append(theInstances[i].second); + } + theDispatch.FireImmediateRefreshInstance(&insts[0], theInstances.size()); + + } else if (CDialogs::shaderExtensions().contains(theExtension) + && theRecord.m_ModificationType != FileModificationType::Created + && !theInstances.empty()) { + std::vector<SMetaDataLoadWarning> theWarnings; + NVScopedRefCounted<qt3ds::render::IRefCountedInputStream> theStream( + m_InputStreamFactory->GetStreamForFile(theRecord.m_File.toQString())); + if (theStream) { + m_MetaData.LoadMaterialInstance(m_StringTable.GetNarrowStr( + theRelativePath.toCString()), + theInstances[0].second, + theRelativePath.GetFileStem().c_str(), + theWarnings, + *theStream); + IDocumentEditor::fixDefaultTexturePaths(theInstances[0].second); } + + for (size_t i = 0; i < theInstances.size(); ++i) + theDispatch.fireReloadMaterialInstance(theInstances[i].second); + } else if (CDialogs::mapExtensions().contains(theExtension) + && theRecord.m_ModificationType != FileModificationType::Created + && !theInstances.empty()) { + imageLoadSet.insert(theRecord.m_File.toQString()); } // There used to be an extension here for meshes // but that causes the product to delete materials in some cases which loses work. - // so that experiment failed and we will just have to let the users manually updated - // their - // meshes through the dropdown if they need them updated. + // so that experiment failed and we will just have to let the users manually update + // their meshes through the dropdown if they need them updated. + } + + + if (!imageLoadSet.isEmpty()) { + auto settings = m_Doc.GetCore()->GetStudioProjectSettings(); + m_Doc.GetBufferCache().reloadImageSet( + IBufferManager::resolveImageSet(imageLoadSet, + settings->getPreferCompressedTextures()), + settings->getFlipCompressedTextures()); } + + g_StudioApp.getRenderer().ReleaseContext(); + if (hasProgressFired) theDispatch.FireOnProgressEnd(); - if (requestRender && m_Doc.GetSceneGraph()) - m_Doc.GetSceneGraph()->RequestRender(); if (hasDispatchNotificationScope) theDispatch.FireEndDataModelNotifications(); + if (requestRender && m_Doc.GetSceneGraph()) + m_Doc.GetSceneGraph()->RenderNow(); } }; } @@ -5383,24 +5681,37 @@ void IDocumentEditor::DisplayImportErrors(const QString &inImportSource, for (size_t idx = 0; idx < inTranslationLog.m_Warnings.size(); ++idx) { const std::pair<ESceneGraphWarningCode, Q3DStudio::CString> &warning( inTranslationLog.m_Warnings[idx]); - const wchar_t *formatStr = L"Unrecognized warning"; + const wchar_t *formatStr = L"Unrecognized warning: \"%ls\""; switch (warning.first) { case ESceneGraphWarningCode_OnlySupportTriangles: - formatStr = L"Model %ls contains geometric elements other than triangles"; + formatStr = L"Model \"%ls\" contains geometric elements other than triangles"; break; case ESceneGraphWarningCode_TrianglesDuplicateSemantic: formatStr = L"Triangle contains duplicate semantics, ex: 1 triangle has multiple " L"TEXCOORD (multiple UV maps)"; break; case ESceneGraphWarningCode_MissingSourceFile: - formatStr = L"Couldn't find a source image file %ls"; + formatStr = L"Couldn't find a source image file \"%ls\""; break; case ESceneGraphWarningCode_LockedDestFile: - formatStr = L"An image or mesh file %ls is not writeable"; + formatStr = L"An image or mesh file \"%ls\" is not writeable"; break; case ESceneGraphWarningCode_VertexBufferTooLarge: formatStr = L"A single mesh exceeds the maximum vertex count of 65535"; break; + case ESceneGraphWarningCode_MissingMaterial: + formatStr = L"Materials are missing from mesh \"%ls\", it was not created"; + break; + case ESceneGraphWarningCode_UnsupportedLight: + formatStr = L"Light type for \"%ls\" is not supported, it was converted to Directional"; + break; + case ESceneGraphWarningCode_Rotations: + formatStr = L"Rotation issue: %ls"; + break; + case ESceneGraphWarningCode_UnknownMaterial: + formatStr = L"Unknown material type(s) encountered. Some material properties may be " + "incorrect. Make sure your FBX export settings are correct."; + break; default: break; } @@ -5446,16 +5757,17 @@ void IDocumentEditor::fixDefaultTexturePaths(Qt3DSDMInstanceHandle instance) = propertySystem->GetAdditionalMetaDataType(instance, prop); if (additionalMetaDataType == AdditionalMetaDataType::Texture) { propertySystem->GetInstancePropertyValue(instance, prop, value); - TDataStrPtr strPtr = get<TDataStrPtr>(value); - const QString strValue = QString::fromWCharArray(strPtr->GetData()); - const QString docRelative = docDir.relativeFilePath(strValue); - const QString projRelative = projDir.relativeFilePath(strValue); - if (!QFileInfo(docRelative).exists() && !QFileInfo(projRelative).exists()) { - // Convert path to presentation relative - const QVariant newVarValue = QVariant::fromValue( - docDir.relativeFilePath(projDir.absoluteFilePath(strValue))); - const SValue newValue = newVarValue; - propertySystem->SetInstancePropertyValue(instance, prop, newValue); + if (value.getType() == DataModelDataType::String) { + TDataStrPtr strPtr = get<TDataStrPtr>(value); + const QString strValue = QString::fromWCharArray(strPtr->GetData()); + const QString docRelative = docDir.relativeFilePath(strValue); + if (!QFileInfo(docDir.filePath(docRelative)).exists()) { + // Convert path to presentation relative + const QVariant newVarValue = QVariant::fromValue( + docDir.relativeFilePath(projDir.absoluteFilePath(strValue))); + const SValue newValue = newVarValue; + propertySystem->SetInstancePropertyValue(instance, prop, newValue); + } } } } @@ -5499,6 +5811,11 @@ Qt3DSDMInstanceHandle IDocumentEditor::CreateSceneGraphInstance( TInstanceHandle theDerivationParent(inMaster); inDataCore.DeriveInstance(retval, theDerivationParent); + // Clear file id derived from the parent + // This happens for custom shaders and causes id conflicts (QT3DS-4018) + inDataCore.SetInstancePropertyValue(retval, inObjectDefs.m_Asset.m_FileId, + std::make_shared<CDataStr>(L"")); + if (inParent.Valid()) inAssetGraph.AddChild(inParent, retval); else |