149 lines
5.2 KiB
C++
149 lines
5.2 KiB
C++
#include "TransformCommand.h"
|
|
#include "../../utils/Logger.h"
|
|
#include <pxr/usd/usd/editContext.h>
|
|
#include <pxr/usd/usdGeom/xformOp.h>
|
|
|
|
namespace UsdLayerManager {
|
|
|
|
// True when attr has an authored time sample exactly at time t.
|
|
static bool HasSampleAtTime(const pxr::UsdAttribute& attr, double t)
|
|
{
|
|
if (!attr) return false;
|
|
std::vector<double> times;
|
|
if (!attr.GetTimeSamples(×)) return false;
|
|
for (double s : times)
|
|
if (s == t) return true;
|
|
return false;
|
|
}
|
|
|
|
// Attribute name of the rotate op XformCommonAPI authors for a rotation order
|
|
// (e.g. "xformOp:rotateXYZ").
|
|
static pxr::TfToken RotateOpName(pxr::UsdGeomXformCommonAPI::RotationOrder ro)
|
|
{
|
|
return pxr::UsdGeomXformOp::GetOpName(
|
|
pxr::UsdGeomXformCommonAPI::ConvertRotationOrderToOpType(ro));
|
|
}
|
|
|
|
TransformCommand::SamplePresence TransformCommand::QuerySamplePresence(
|
|
pxr::UsdStageRefPtr stage,
|
|
const pxr::SdfPath& primPath,
|
|
pxr::UsdGeomXformCommonAPI::RotationOrder rotOrder,
|
|
pxr::UsdTimeCode timeCode)
|
|
{
|
|
SamplePresence presence;
|
|
if (timeCode.IsDefault() || !stage) return presence;
|
|
pxr::UsdPrim prim = stage->GetPrimAtPath(primPath);
|
|
if (!prim) return presence;
|
|
|
|
double t = timeCode.GetValue();
|
|
presence.translate = HasSampleAtTime(
|
|
prim.GetAttribute(pxr::UsdGeomXformOp::GetOpName(
|
|
pxr::UsdGeomXformOp::TypeTranslate)), t);
|
|
presence.rotate = HasSampleAtTime(
|
|
prim.GetAttribute(RotateOpName(rotOrder)), t);
|
|
presence.scale = HasSampleAtTime(
|
|
prim.GetAttribute(pxr::UsdGeomXformOp::GetOpName(
|
|
pxr::UsdGeomXformOp::TypeScale)), t);
|
|
return presence;
|
|
}
|
|
|
|
TransformCommand::TransformCommand(pxr::UsdStageRefPtr stage,
|
|
const pxr::SdfPath& primPath,
|
|
pxr::SdfLayerHandle editLayer,
|
|
const pxr::GfVec3d& oldTranslate,
|
|
const pxr::GfVec3f& oldRotate,
|
|
const pxr::GfVec3f& oldScale,
|
|
const pxr::GfVec3d& newTranslate,
|
|
const pxr::GfVec3f& newRotate,
|
|
const pxr::GfVec3f& newScale,
|
|
pxr::UsdGeomXformCommonAPI::RotationOrder rotOrder,
|
|
pxr::UsdTimeCode timeCode,
|
|
SamplePresence preEditSamples,
|
|
std::string description)
|
|
: m_stage(stage)
|
|
, m_primPath(primPath)
|
|
, m_editLayer(editLayer)
|
|
, m_oldTranslate(oldTranslate)
|
|
, m_oldRotate(oldRotate)
|
|
, m_oldScale(oldScale)
|
|
, m_newTranslate(newTranslate)
|
|
, m_newRotate(newRotate)
|
|
, m_newScale(newScale)
|
|
, m_rotOrder(rotOrder)
|
|
, m_timeCode(timeCode)
|
|
, m_description(std::move(description))
|
|
, m_preEditSamples(preEditSamples)
|
|
{
|
|
}
|
|
|
|
void TransformCommand::Execute() {
|
|
Apply(m_newTranslate, m_newRotate, m_newScale);
|
|
}
|
|
|
|
void TransformCommand::Undo() {
|
|
Apply(m_oldTranslate, m_oldRotate, m_oldScale);
|
|
ClearCreatedSamples();
|
|
}
|
|
|
|
void TransformCommand::Apply(const pxr::GfVec3d& t,
|
|
const pxr::GfVec3f& r,
|
|
const pxr::GfVec3f& s)
|
|
{
|
|
if (!m_stage || m_primPath.IsEmpty()) return;
|
|
pxr::UsdPrim prim = m_stage->GetPrimAtPath(m_primPath);
|
|
if (!prim) return;
|
|
|
|
pxr::UsdGeomXformCommonAPI api(prim);
|
|
if (!api) return;
|
|
|
|
try {
|
|
if (m_editLayer) {
|
|
pxr::UsdEditContext ec(m_stage, m_editLayer);
|
|
api.SetTranslate(t, m_timeCode);
|
|
api.SetRotate(r, m_rotOrder, m_timeCode);
|
|
api.SetScale(s, m_timeCode);
|
|
} else {
|
|
api.SetTranslate(t, m_timeCode);
|
|
api.SetRotate(r, m_rotOrder, m_timeCode);
|
|
api.SetScale(s, m_timeCode);
|
|
}
|
|
} catch (const std::exception& e) {
|
|
LOG_ERROR(std::string("TransformCommand::Apply error: ") + e.what());
|
|
}
|
|
}
|
|
|
|
void TransformCommand::ClearCreatedSamples()
|
|
{
|
|
if (m_timeCode.IsDefault()) return;
|
|
if (!m_stage || m_primPath.IsEmpty()) return;
|
|
pxr::UsdPrim prim = m_stage->GetPrimAtPath(m_primPath);
|
|
if (!prim) return;
|
|
|
|
auto clearOp = [&](const pxr::TfToken& opName, bool hadSample) {
|
|
if (hadSample) return;
|
|
pxr::UsdAttribute attr = prim.GetAttribute(opName);
|
|
if (attr) attr.ClearAtTime(m_timeCode);
|
|
};
|
|
|
|
auto clearAll = [&]() {
|
|
clearOp(pxr::UsdGeomXformOp::GetOpName(
|
|
pxr::UsdGeomXformOp::TypeTranslate), m_preEditSamples.translate);
|
|
clearOp(RotateOpName(m_rotOrder), m_preEditSamples.rotate);
|
|
clearOp(pxr::UsdGeomXformOp::GetOpName(
|
|
pxr::UsdGeomXformOp::TypeScale), m_preEditSamples.scale);
|
|
};
|
|
|
|
try {
|
|
if (m_editLayer) {
|
|
pxr::UsdEditContext ec(m_stage, m_editLayer);
|
|
clearAll();
|
|
} else {
|
|
clearAll();
|
|
}
|
|
} catch (const std::exception& e) {
|
|
LOG_ERROR(std::string("TransformCommand::ClearCreatedSamples error: ") + e.what());
|
|
}
|
|
}
|
|
|
|
} // namespace UsdLayerManager
|