Merge branch 'master' into sculpt-dev

This commit is contained in:
Pablo Dobarro 2020-12-23 19:23:03 +01:00
commit f32d3f7b06
54 changed files with 2851 additions and 540 deletions

View File

@ -200,6 +200,7 @@ set(SRC
${MANTA_PP}/plugin/ptsplugins.cpp
${MANTA_PP}/plugin/secondaryparticles.cpp
${MANTA_PP}/plugin/surfaceturbulence.cpp
${MANTA_PP}/plugin/viscosity.cpp
${MANTA_PP}/plugin/vortexplugins.cpp
${MANTA_PP}/plugin/waveletturbulence.cpp
${MANTA_PP}/plugin/waves.cpp

View File

@ -1035,7 +1035,7 @@ template<class N, class T> struct RCFixedMatrix {
typedef RCMatrix<int, Real> Matrix;
typedef RCFixedMatrix<int, Real> FixedMatrix;
} // namespace Manta
}
#undef parallel_for
#undef parallel_end

View File

@ -397,7 +397,7 @@ struct UpdateSearchVec : public KernelBase {
};
//*****************************************************************************
// CG class
// CG class
template<class APPLYMAT>
GridCg<APPLYMAT>::GridCg(Grid<Real> &dst,
@ -406,10 +406,8 @@ GridCg<APPLYMAT>::GridCg(Grid<Real> &dst,
Grid<Real> &search,
const FlagGrid &flags,
Grid<Real> &tmp,
Grid<Real> *pA0,
Grid<Real> *pAi,
Grid<Real> *pAj,
Grid<Real> *pAk)
std::vector<Grid<Real> *> matrixAVec,
std::vector<Grid<Real> *> rhsVec)
: GridCgInterface(),
mInited(false),
mIterations(0),
@ -419,10 +417,8 @@ GridCg<APPLYMAT>::GridCg(Grid<Real> &dst,
mSearch(search),
mFlags(flags),
mTmp(tmp),
mpA0(pA0),
mpAi(pAi),
mpAj(pAj),
mpAk(pAk),
mMatrixA(matrixAVec),
mVecRhs(rhsVec),
mPcMethod(PC_None),
mpPCA0(nullptr),
mpPCAi(nullptr),
@ -445,19 +441,37 @@ template<class APPLYMAT> void GridCg<APPLYMAT>::doInit()
if (mPcMethod == PC_ICP) {
assertMsg(mDst.is3D(), "ICP only supports 3D grids so far");
InitPreconditionIncompCholesky(
mFlags, *mpPCA0, *mpPCAi, *mpPCAj, *mpPCAk, *mpA0, *mpAi, *mpAj, *mpAk);
ApplyPreconditionIncompCholesky(
mTmp, mResidual, mFlags, *mpPCA0, *mpPCAi, *mpPCAj, *mpPCAk, *mpA0, *mpAi, *mpAj, *mpAk);
InitPreconditionIncompCholesky(mFlags,
*mpPCA0,
*mpPCAi,
*mpPCAj,
*mpPCAk,
*mMatrixA[0],
*mMatrixA[1],
*mMatrixA[2],
*mMatrixA[3]);
ApplyPreconditionIncompCholesky(mTmp,
mResidual,
mFlags,
*mpPCA0,
*mpPCAi,
*mpPCAj,
*mpPCAk,
*mMatrixA[0],
*mMatrixA[1],
*mMatrixA[2],
*mMatrixA[3]);
}
else if (mPcMethod == PC_mICP) {
assertMsg(mDst.is3D(), "mICP only supports 3D grids so far");
InitPreconditionModifiedIncompCholesky2(mFlags, *mpPCA0, *mpA0, *mpAi, *mpAj, *mpAk);
InitPreconditionModifiedIncompCholesky2(
mFlags, *mpPCA0, *mMatrixA[0], *mMatrixA[1], *mMatrixA[2], *mMatrixA[3]);
ApplyPreconditionModifiedIncompCholesky2(
mTmp, mResidual, mFlags, *mpPCA0, *mpA0, *mpAi, *mpAj, *mpAk);
mTmp, mResidual, mFlags, *mpPCA0, *mMatrixA[0], *mMatrixA[1], *mMatrixA[2], *mMatrixA[3]);
}
else if (mPcMethod == PC_MGP) {
InitPreconditionMultigrid(mMG, *mpA0, *mpAi, *mpAj, *mpAk, mAccuracy);
InitPreconditionMultigrid(
mMG, *mMatrixA[0], *mMatrixA[1], *mMatrixA[2], *mMatrixA[3], mAccuracy);
ApplyPreconditionMultigrid(mMG, mTmp, mResidual);
}
else {
@ -465,7 +479,6 @@ template<class APPLYMAT> void GridCg<APPLYMAT>::doInit()
}
mSearch.copyFrom(mTmp);
mSigma = GridDotProduct(mTmp, mResidual);
}
@ -480,7 +493,7 @@ template<class APPLYMAT> bool GridCg<APPLYMAT>::iterate()
// this could reinterpret the mpA pointers (not so clean right now)
// tmp = applyMat(search)
APPLYMAT(mFlags, mTmp, mSearch, *mpA0, *mpAi, *mpAj, *mpAk);
APPLYMAT(mFlags, mTmp, mSearch, mMatrixA, mVecRhs);
// alpha = sigma/dot(tmp, search)
Real dp = GridDotProduct(mTmp, mSearch);
@ -492,11 +505,20 @@ template<class APPLYMAT> bool GridCg<APPLYMAT>::iterate()
gridScaledAdd<Real, Real>(mResidual, mTmp, -alpha); // residual += tmp * -alpha
if (mPcMethod == PC_ICP)
ApplyPreconditionIncompCholesky(
mTmp, mResidual, mFlags, *mpPCA0, *mpPCAi, *mpPCAj, *mpPCAk, *mpA0, *mpAi, *mpAj, *mpAk);
ApplyPreconditionIncompCholesky(mTmp,
mResidual,
mFlags,
*mpPCA0,
*mpPCAi,
*mpPCAj,
*mpPCAk,
*mMatrixA[0],
*mMatrixA[1],
*mMatrixA[2],
*mMatrixA[3]);
else if (mPcMethod == PC_mICP)
ApplyPreconditionModifiedIncompCholesky2(
mTmp, mResidual, mFlags, *mpPCA0, *mpA0, *mpAi, *mpAj, *mpAk);
mTmp, mResidual, mFlags, *mpPCA0, *mMatrixA[0], *mMatrixA[1], *mMatrixA[2], *mMatrixA[3]);
else if (mPcMethod == PC_MGP)
ApplyPreconditionMultigrid(mMG, mTmp, mResidual);
else
@ -584,13 +606,15 @@ void GridCg<APPLYMAT>::setMGPreconditioner(PreconditionType method, GridMg *MG)
assertMsg(method == PC_MGP, "GridCg<APPLYMAT>::setMGPreconditioner: Invalid method specified.");
mPcMethod = method;
mMG = MG;
}
// explicit instantiation
template class GridCg<ApplyMatrix>;
template class GridCg<ApplyMatrix2D>;
template class GridCg<ApplyMatrixViscosityU>;
template class GridCg<ApplyMatrixViscosityV>;
template class GridCg<ApplyMatrixViscosityW>;
//*****************************************************************************
// diffusion for real and vec grids, e.g. for viscosity
@ -638,10 +662,15 @@ void cgSolveDiffusion(const FlagGrid &flags,
if (grid.getType() & GridBase::TypeReal) {
Grid<Real> &u = ((Grid<Real> &)grid);
rhs.copyFrom(u);
if (flags.is3D())
gcg = new GridCg<ApplyMatrix>(u, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak);
else
gcg = new GridCg<ApplyMatrix2D>(u, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak);
vector<Grid<Real> *> matA{&A0, &Ai, &Aj};
if (flags.is3D()) {
matA.push_back(&Ak);
gcg = new GridCg<ApplyMatrix>(u, rhs, residual, search, flags, tmp, matA);
}
else {
gcg = new GridCg<ApplyMatrix2D>(u, rhs, residual, search, flags, tmp, matA);
}
gcg->setAccuracy(cgAccuracy);
gcg->solve(maxIter);
@ -653,12 +682,17 @@ void cgSolveDiffusion(const FlagGrid &flags,
else if ((grid.getType() & GridBase::TypeVec3) || (grid.getType() & GridBase::TypeMAC)) {
Grid<Vec3> &vec = ((Grid<Vec3> &)grid);
Grid<Real> u(parent);
vector<Grid<Real> *> matA{&A0, &Ai, &Aj};
// core solve is same as for a regular real grid
if (flags.is3D())
gcg = new GridCg<ApplyMatrix>(u, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak);
else
gcg = new GridCg<ApplyMatrix2D>(u, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak);
if (flags.is3D()) {
matA.push_back(&Ak);
gcg = new GridCg<ApplyMatrix>(u, rhs, residual, search, flags, tmp, matA);
}
else {
gcg = new GridCg<ApplyMatrix2D>(u, rhs, residual, search, flags, tmp, matA);
}
gcg->setAccuracy(cgAccuracy);
// diffuse every component separately

View File

@ -78,13 +78,9 @@ template<class APPLYMAT> class GridCg : public GridCgInterface {
Grid<Real> &search,
const FlagGrid &flags,
Grid<Real> &tmp,
Grid<Real> *A0,
Grid<Real> *pAi,
Grid<Real> *pAj,
Grid<Real> *pAk);
~GridCg()
{
}
std::vector<Grid<Real> *> matrixAVec,
std::vector<Grid<Real> *> rhsVec = {});
~GridCg(){};
void doInit();
bool iterate();
@ -133,7 +129,10 @@ template<class APPLYMAT> class GridCg : public GridCgInterface {
const FlagGrid &mFlags;
Grid<Real> &mTmp;
Grid<Real> *mpA0, *mpAi, *mpAj, *mpAk;
//! shape of A matrix defined here (e.g. diagonal, positive neighbor cells, etc)
std::vector<Grid<Real> *> mMatrixA;
//! shape of rhs vector defined here (e.g. 1 rhs for regular fluids solve, 3 rhs for viscosity)
std::vector<Grid<Real> *> mVecRhs;
PreconditionType mPcMethod;
//! preconditioning grids
@ -154,11 +153,9 @@ struct ApplyMatrix : public KernelBase {
ApplyMatrix(const FlagGrid &flags,
Grid<Real> &dst,
const Grid<Real> &src,
Grid<Real> &A0,
Grid<Real> &Ai,
Grid<Real> &Aj,
Grid<Real> &Ak)
: KernelBase(&flags, 0), flags(flags), dst(dst), src(src), A0(A0), Ai(Ai), Aj(Aj), Ak(Ak)
const std::vector<Grid<Real> *> matrixA,
const std::vector<Grid<Real> *> vecRhs)
: KernelBase(&flags, 0), flags(flags), dst(dst), src(src), matrixA(matrixA), vecRhs(vecRhs)
{
runMessage();
run();
@ -167,11 +164,18 @@ struct ApplyMatrix : public KernelBase {
const FlagGrid &flags,
Grid<Real> &dst,
const Grid<Real> &src,
Grid<Real> &A0,
Grid<Real> &Ai,
Grid<Real> &Aj,
Grid<Real> &Ak) const
const std::vector<Grid<Real> *> matrixA,
const std::vector<Grid<Real> *> vecRhs) const
{
unusedParameter(vecRhs); // Not needed in this matrix application
if (matrixA.size() != 4)
errMsg("ConjugatedGrad: Invalid A matrix in apply matrix step");
Grid<Real> &A0 = *matrixA[0];
Grid<Real> &Ai = *matrixA[1];
Grid<Real> &Aj = *matrixA[2];
Grid<Real> &Ak = *matrixA[3];
if (!flags.isFluid(idx)) {
dst[idx] = src[idx];
return;
@ -196,26 +200,16 @@ struct ApplyMatrix : public KernelBase {
return src;
}
typedef Grid<Real> type2;
inline Grid<Real> &getArg3()
inline const std::vector<Grid<Real> *> &getArg3()
{
return A0;
return matrixA;
}
typedef Grid<Real> type3;
inline Grid<Real> &getArg4()
typedef std::vector<Grid<Real> *> type3;
inline const std::vector<Grid<Real> *> &getArg4()
{
return Ai;
return vecRhs;
}
typedef Grid<Real> type4;
inline Grid<Real> &getArg5()
{
return Aj;
}
typedef Grid<Real> type5;
inline Grid<Real> &getArg6()
{
return Ak;
}
typedef Grid<Real> type6;
typedef std::vector<Grid<Real> *> type4;
void runMessage()
{
debMsg("Executing kernel ApplyMatrix ", 3);
@ -226,7 +220,7 @@ struct ApplyMatrix : public KernelBase {
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
op(idx, flags, dst, src, A0, Ai, Aj, Ak);
op(idx, flags, dst, src, matrixA, vecRhs);
}
void run()
{
@ -235,10 +229,8 @@ struct ApplyMatrix : public KernelBase {
const FlagGrid &flags;
Grid<Real> &dst;
const Grid<Real> &src;
Grid<Real> &A0;
Grid<Real> &Ai;
Grid<Real> &Aj;
Grid<Real> &Ak;
const std::vector<Grid<Real> *> matrixA;
const std::vector<Grid<Real> *> vecRhs;
};
//! Kernel: Apply symmetric stored Matrix. 2D version
@ -247,11 +239,9 @@ struct ApplyMatrix2D : public KernelBase {
ApplyMatrix2D(const FlagGrid &flags,
Grid<Real> &dst,
const Grid<Real> &src,
Grid<Real> &A0,
Grid<Real> &Ai,
Grid<Real> &Aj,
Grid<Real> &Ak)
: KernelBase(&flags, 0), flags(flags), dst(dst), src(src), A0(A0), Ai(Ai), Aj(Aj), Ak(Ak)
const std::vector<Grid<Real> *> matrixA,
const std::vector<Grid<Real> *> vecRhs)
: KernelBase(&flags, 0), flags(flags), dst(dst), src(src), matrixA(matrixA), vecRhs(vecRhs)
{
runMessage();
run();
@ -260,12 +250,16 @@ struct ApplyMatrix2D : public KernelBase {
const FlagGrid &flags,
Grid<Real> &dst,
const Grid<Real> &src,
Grid<Real> &A0,
Grid<Real> &Ai,
Grid<Real> &Aj,
Grid<Real> &Ak) const
const std::vector<Grid<Real> *> matrixA,
const std::vector<Grid<Real> *> vecRhs) const
{
unusedParameter(Ak); // only there for parameter compatibility with ApplyMatrix
unusedParameter(vecRhs); // Not needed in this matrix application
if (matrixA.size() != 3)
errMsg("ConjugatedGrad: Invalid A matrix in apply matrix step");
Grid<Real> &A0 = *matrixA[0];
Grid<Real> &Ai = *matrixA[1];
Grid<Real> &Aj = *matrixA[2];
if (!flags.isFluid(idx)) {
dst[idx] = src[idx];
@ -290,26 +284,16 @@ struct ApplyMatrix2D : public KernelBase {
return src;
}
typedef Grid<Real> type2;
inline Grid<Real> &getArg3()
inline const std::vector<Grid<Real> *> &getArg3()
{
return A0;
return matrixA;
}
typedef Grid<Real> type3;
inline Grid<Real> &getArg4()
typedef std::vector<Grid<Real> *> type3;
inline const std::vector<Grid<Real> *> &getArg4()
{
return Ai;
return vecRhs;
}
typedef Grid<Real> type4;
inline Grid<Real> &getArg5()
{
return Aj;
}
typedef Grid<Real> type5;
inline Grid<Real> &getArg6()
{
return Ak;
}
typedef Grid<Real> type6;
typedef std::vector<Grid<Real> *> type4;
void runMessage()
{
debMsg("Executing kernel ApplyMatrix2D ", 3);
@ -320,7 +304,7 @@ struct ApplyMatrix2D : public KernelBase {
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
op(idx, flags, dst, src, A0, Ai, Aj, Ak);
op(idx, flags, dst, src, matrixA, vecRhs);
}
void run()
{
@ -329,12 +313,358 @@ struct ApplyMatrix2D : public KernelBase {
const FlagGrid &flags;
Grid<Real> &dst;
const Grid<Real> &src;
Grid<Real> &A0;
Grid<Real> &Ai;
Grid<Real> &Aj;
Grid<Real> &Ak;
const std::vector<Grid<Real> *> matrixA;
const std::vector<Grid<Real> *> vecRhs;
};
struct ApplyMatrixViscosityU : public KernelBase {
ApplyMatrixViscosityU(const FlagGrid &flags,
Grid<Real> &dst,
const Grid<Real> &src,
const std::vector<Grid<Real> *> matrixA,
const std::vector<Grid<Real> *> vecRhs)
: KernelBase(&flags, 1), flags(flags), dst(dst), src(src), matrixA(matrixA), vecRhs(vecRhs)
{
runMessage();
run();
}
inline void op(int i,
int j,
int k,
const FlagGrid &flags,
Grid<Real> &dst,
const Grid<Real> &src,
const std::vector<Grid<Real> *> matrixA,
const std::vector<Grid<Real> *> vecRhs) const
{
if (matrixA.size() != 15)
errMsg("ConjugatedGrad: Invalid A matrix in apply matrix step");
Grid<Real> &A0 = *matrixA[0];
Grid<Real> &Aplusi = *matrixA[1];
Grid<Real> &Aplusj = *matrixA[2];
Grid<Real> &Aplusk = *matrixA[3];
Grid<Real> &Aminusi = *matrixA[4];
Grid<Real> &Aminusj = *matrixA[5];
Grid<Real> &Aminusk = *matrixA[6];
if (vecRhs.size() != 2)
errMsg("ConjugatedGrad: Invalid rhs vector in apply matrix step");
Grid<Real> &srcV = *vecRhs[0];
Grid<Real> &srcW = *vecRhs[1];
dst(i, j, k) = src(i, j, k) * A0(i, j, k) + src(i + 1, j, k) * Aplusi(i, j, k) +
src(i, j + 1, k) * Aplusj(i, j, k) + src(i, j, k + 1) * Aplusk(i, j, k) +
src(i - 1, j, k) * Aminusi(i, j, k) + src(i, j - 1, k) * Aminusj(i, j, k) +
src(i, j, k - 1) * Aminusk(i, j, k);
dst(i, j, k) += srcV(i, j + 1, k) * (*matrixA[7])(i, j, k) +
srcV(i - 1, j + 1, k) * (*matrixA[8])(i, j, k) +
srcV(i, j, k) * (*matrixA[9])(i, j, k) +
srcV(i - 1, j, k) * (*matrixA[10])(i, j, k) +
srcW(i, j, k + 1) * (*matrixA[11])(i, j, k) +
srcW(i - 1, j, k + 1) * (*matrixA[12])(i, j, k) +
srcW(i, j, k) * (*matrixA[13])(i, j, k) +
srcW(i - 1, j, k) * (*matrixA[14])(i, j, k);
}
inline const FlagGrid &getArg0()
{
return flags;
}
typedef FlagGrid type0;
inline Grid<Real> &getArg1()
{
return dst;
}
typedef Grid<Real> type1;
inline const Grid<Real> &getArg2()
{
return src;
}
typedef Grid<Real> type2;
inline const std::vector<Grid<Real> *> &getArg3()
{
return matrixA;
}
typedef std::vector<Grid<Real> *> type3;
inline const std::vector<Grid<Real> *> &getArg4()
{
return vecRhs;
}
typedef std::vector<Grid<Real> *> type4;
void runMessage()
{
debMsg("Executing kernel ApplyMatrixViscosityU ", 3);
debMsg("Kernel range"
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
const int _maxX = maxX;
const int _maxY = maxY;
if (maxZ > 1) {
for (int k = __r.begin(); k != (int)__r.end(); k++)
for (int j = 1; j < _maxY; j++)
for (int i = 1; i < _maxX; i++)
op(i, j, k, flags, dst, src, matrixA, vecRhs);
}
else {
const int k = 0;
for (int j = __r.begin(); j != (int)__r.end(); j++)
for (int i = 1; i < _maxX; i++)
op(i, j, k, flags, dst, src, matrixA, vecRhs);
}
}
void run()
{
if (maxZ > 1)
tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
else
tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
}
const FlagGrid &flags;
Grid<Real> &dst;
const Grid<Real> &src;
const std::vector<Grid<Real> *> matrixA;
const std::vector<Grid<Real> *> vecRhs;
};
struct ApplyMatrixViscosityV : public KernelBase {
ApplyMatrixViscosityV(const FlagGrid &flags,
Grid<Real> &dst,
const Grid<Real> &src,
const std::vector<Grid<Real> *> matrixA,
const std::vector<Grid<Real> *> vecRhs)
: KernelBase(&flags, 1), flags(flags), dst(dst), src(src), matrixA(matrixA), vecRhs(vecRhs)
{
runMessage();
run();
}
inline void op(int i,
int j,
int k,
const FlagGrid &flags,
Grid<Real> &dst,
const Grid<Real> &src,
const std::vector<Grid<Real> *> matrixA,
const std::vector<Grid<Real> *> vecRhs) const
{
if (matrixA.size() != 15)
errMsg("ConjugatedGrad: Invalid A matrix in apply matrix step");
Grid<Real> &A0 = *matrixA[0];
Grid<Real> &Aplusi = *matrixA[1];
Grid<Real> &Aplusj = *matrixA[2];
Grid<Real> &Aplusk = *matrixA[3];
Grid<Real> &Aminusi = *matrixA[4];
Grid<Real> &Aminusj = *matrixA[5];
Grid<Real> &Aminusk = *matrixA[6];
if (vecRhs.size() != 2)
errMsg("ConjugatedGrad: Invalid rhs vector in apply matrix step");
Grid<Real> &srcU = *vecRhs[0];
Grid<Real> &srcW = *vecRhs[1];
dst(i, j, k) = src(i, j, k) * A0(i, j, k) + src(i + 1, j, k) * Aplusi(i, j, k) +
src(i, j + 1, k) * Aplusj(i, j, k) + src(i, j, k + 1) * Aplusk(i, j, k) +
src(i - 1, j, k) * Aminusi(i, j, k) + src(i, j - 1, k) * Aminusj(i, j, k) +
src(i, j, k - 1) * Aminusk(i, j, k);
dst(i, j, k) += srcU(i + 1, j, k) * (*matrixA[7])(i, j, k) +
srcU(i + 1, j - 1, k) * (*matrixA[8])(i, j, k) +
srcU(i, j, k) * (*matrixA[9])(i, j, k) +
srcU(i, j - 1, k) * (*matrixA[10])(i, j, k) +
srcW(i, j, k + 1) * (*matrixA[11])(i, j, k) +
srcW(i, j - 1, k + 1) * (*matrixA[12])(i, j, k) +
srcW(i, j, k) * (*matrixA[13])(i, j, k) +
srcW(i, j - 1, k) * (*matrixA[14])(i, j, k);
}
inline const FlagGrid &getArg0()
{
return flags;
}
typedef FlagGrid type0;
inline Grid<Real> &getArg1()
{
return dst;
}
typedef Grid<Real> type1;
inline const Grid<Real> &getArg2()
{
return src;
}
typedef Grid<Real> type2;
inline const std::vector<Grid<Real> *> &getArg3()
{
return matrixA;
}
typedef std::vector<Grid<Real> *> type3;
inline const std::vector<Grid<Real> *> &getArg4()
{
return vecRhs;
}
typedef std::vector<Grid<Real> *> type4;
void runMessage()
{
debMsg("Executing kernel ApplyMatrixViscosityV ", 3);
debMsg("Kernel range"
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
const int _maxX = maxX;
const int _maxY = maxY;
if (maxZ > 1) {
for (int k = __r.begin(); k != (int)__r.end(); k++)
for (int j = 1; j < _maxY; j++)
for (int i = 1; i < _maxX; i++)
op(i, j, k, flags, dst, src, matrixA, vecRhs);
}
else {
const int k = 0;
for (int j = __r.begin(); j != (int)__r.end(); j++)
for (int i = 1; i < _maxX; i++)
op(i, j, k, flags, dst, src, matrixA, vecRhs);
}
}
void run()
{
if (maxZ > 1)
tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
else
tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
}
const FlagGrid &flags;
Grid<Real> &dst;
const Grid<Real> &src;
const std::vector<Grid<Real> *> matrixA;
const std::vector<Grid<Real> *> vecRhs;
};
struct ApplyMatrixViscosityW : public KernelBase {
ApplyMatrixViscosityW(const FlagGrid &flags,
Grid<Real> &dst,
const Grid<Real> &src,
const std::vector<Grid<Real> *> matrixA,
const std::vector<Grid<Real> *> vecRhs)
: KernelBase(&flags, 1), flags(flags), dst(dst), src(src), matrixA(matrixA), vecRhs(vecRhs)
{
runMessage();
run();
}
inline void op(int i,
int j,
int k,
const FlagGrid &flags,
Grid<Real> &dst,
const Grid<Real> &src,
const std::vector<Grid<Real> *> matrixA,
const std::vector<Grid<Real> *> vecRhs) const
{
if (matrixA.size() != 15)
errMsg("ConjugatedGrad: Invalid A matrix in apply matrix step");
Grid<Real> &A0 = *matrixA[0];
Grid<Real> &Aplusi = *matrixA[1];
Grid<Real> &Aplusj = *matrixA[2];
Grid<Real> &Aplusk = *matrixA[3];
Grid<Real> &Aminusi = *matrixA[4];
Grid<Real> &Aminusj = *matrixA[5];
Grid<Real> &Aminusk = *matrixA[6];
if (vecRhs.size() != 2)
errMsg("ConjugatedGrad: Invalid rhs vector in apply matrix step");
Grid<Real> &srcU = *vecRhs[0];
Grid<Real> &srcV = *vecRhs[1];
dst(i, j, k) = src(i, j, k) * A0(i, j, k) + src(i + 1, j, k) * Aplusi(i, j, k) +
src(i, j + 1, k) * Aplusj(i, j, k) + src(i, j, k + 1) * Aplusk(i, j, k) +
src(i - 1, j, k) * Aminusi(i, j, k) + src(i, j - 1, k) * Aminusj(i, j, k) +
src(i, j, k - 1) * Aminusk(i, j, k);
dst(i, j, k) += srcU(i + 1, j, k) * (*matrixA[7])(i, j, k) +
srcU(i + 1, j, k - 1) * (*matrixA[8])(i, j, k) +
srcU(i, j, k) * (*matrixA[9])(i, j, k) +
srcU(i, j, k - 1) * (*matrixA[10])(i, j, k) +
srcV(i, j + 1, k) * (*matrixA[11])(i, j, k) +
srcV(i, j + 1, k - 1) * (*matrixA[12])(i, j, k) +
srcV(i, j, k) * (*matrixA[13])(i, j, k) +
srcV(i, j, k - 1) * (*matrixA[14])(i, j, k);
}
inline const FlagGrid &getArg0()
{
return flags;
}
typedef FlagGrid type0;
inline Grid<Real> &getArg1()
{
return dst;
}
typedef Grid<Real> type1;
inline const Grid<Real> &getArg2()
{
return src;
}
typedef Grid<Real> type2;
inline const std::vector<Grid<Real> *> &getArg3()
{
return matrixA;
}
typedef std::vector<Grid<Real> *> type3;
inline const std::vector<Grid<Real> *> &getArg4()
{
return vecRhs;
}
typedef std::vector<Grid<Real> *> type4;
void runMessage()
{
debMsg("Executing kernel ApplyMatrixViscosityW ", 3);
debMsg("Kernel range"
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
const int _maxX = maxX;
const int _maxY = maxY;
if (maxZ > 1) {
for (int k = __r.begin(); k != (int)__r.end(); k++)
for (int j = 1; j < _maxY; j++)
for (int i = 1; i < _maxX; i++)
op(i, j, k, flags, dst, src, matrixA, vecRhs);
}
else {
const int k = 0;
for (int j = __r.begin(); j != (int)__r.end(); j++)
for (int i = 1; i < _maxX; i++)
op(i, j, k, flags, dst, src, matrixA, vecRhs);
}
}
void run()
{
if (maxZ > 1)
tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
else
tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
}
const FlagGrid &flags;
Grid<Real> &dst;
const Grid<Real> &src;
const std::vector<Grid<Real> *> matrixA;
const std::vector<Grid<Real> *> vecRhs;
};
/* NOTE: Use this template for new matrix application kernels
//! Template for matrix application kernels
KERNEL()
void ApplyMatrixTemplate (const FlagGrid& flags, Grid<Real>& dst, const Grid<Real>& src,
const std::vector<Grid<Real> *> matrixA, const std::vector<Grid<Real> *> vecRhs)
{
// The kernel must define how to use the grids from the matrixA and vecRhs lists
}
*/
//! Kernel: Construct the matrix for the poisson equation
struct MakeLaplaceMatrix : public KernelBase {

View File

@ -42,7 +42,7 @@ inline void updateQtGui(bool full, int frame, float time, const std::string &cur
# ifdef _DEBUG
# define DEBUG 1
# endif // _DEBUG
#endif // DEBUG
#endif // DEBUG
// Standard exception
class Error : public std::exception {
@ -242,6 +242,39 @@ inline bool c_isnan(float c)
return d != d;
}
//! Swap so that a<b
template<class T> inline void sort(T &a, T &b)
{
if (a > b)
std::swap(a, b);
}
//! Swap so that a<b<c
template<class T> inline void sort(T &a, T &b, T &c)
{
if (a > b)
std::swap(a, b);
if (a > c)
std::swap(a, c);
if (b > c)
std::swap(b, c);
}
//! Swap so that a<b<c<d
template<class T> inline void sort(T &a, T &b, T &c, T &d)
{
if (a > b)
std::swap(a, b);
if (c > d)
std::swap(c, d);
if (a > c)
std::swap(a, c);
if (b > d)
std::swap(b, d);
if (b > c)
std::swap(b, c);
}
} // namespace Manta
#endif

View File

@ -1,3 +1,3 @@
#define MANTA_GIT_VERSION "commit 327917cd59b03bef3a953b5f58fc1637b3a83e01"
#define MANTA_GIT_VERSION "commit e2285cb9bc492987f728123be6cfc1fe11fe73d6"

View File

@ -1135,26 +1135,27 @@ struct KnAddForceIfLower : public KernelBase {
if (!curFluid && !curEmpty)
return;
Real minVal, maxVal, sum;
if (flags.isFluid(i - 1, j, k) || (curFluid && flags.isEmpty(i - 1, j, k))) {
Real forceMACX = 0.5 * (force(i - 1, j, k).x + force(i, j, k).x);
Real min = std::min(vel(i, j, k).x, forceMACX);
Real max = std::max(vel(i, j, k).x, forceMACX);
Real sum = vel(i, j, k).x + forceMACX;
vel(i, j, k).x = (forceMACX > 0) ? std::min(sum, max) : std::max(sum, min);
minVal = min(vel(i, j, k).x, forceMACX);
maxVal = max(vel(i, j, k).x, forceMACX);
sum = vel(i, j, k).x + forceMACX;
vel(i, j, k).x = (forceMACX > 0) ? min(sum, maxVal) : max(sum, minVal);
}
if (flags.isFluid(i, j - 1, k) || (curFluid && flags.isEmpty(i, j - 1, k))) {
Real forceMACY = 0.5 * (force(i, j - 1, k).y + force(i, j, k).y);
Real min = std::min(vel(i, j, k).y, forceMACY);
Real max = std::max(vel(i, j, k).y, forceMACY);
Real sum = vel(i, j, k).y + forceMACY;
vel(i, j, k).y = (forceMACY > 0) ? std::min(sum, max) : std::max(sum, min);
minVal = min(vel(i, j, k).y, forceMACY);
maxVal = max(vel(i, j, k).y, forceMACY);
sum = vel(i, j, k).y + forceMACY;
vel(i, j, k).y = (forceMACY > 0) ? min(sum, maxVal) : max(sum, minVal);
}
if (vel.is3D() && (flags.isFluid(i, j, k - 1) || (curFluid && flags.isEmpty(i, j, k - 1)))) {
Real forceMACZ = 0.5 * (force(i, j, k - 1).z + force(i, j, k).z);
Real min = std::min(vel(i, j, k).z, forceMACZ);
Real max = std::max(vel(i, j, k).z, forceMACZ);
Real sum = vel(i, j, k).z + forceMACZ;
vel(i, j, k).z = (forceMACZ > 0) ? std::min(sum, max) : std::max(sum, min);
minVal = min(vel(i, j, k).z, forceMACZ);
maxVal = max(vel(i, j, k).z, forceMACZ);
sum = vel(i, j, k).z + forceMACZ;
vel(i, j, k).z = (forceMACZ > 0) ? min(sum, maxVal) : max(sum, minVal);
}
}
inline const FlagGrid &getArg0()

View File

@ -1138,11 +1138,15 @@ void solvePressureSystem(Grid<Real> &rhs,
// note: the last factor increases the max iterations for 2d, which right now can't use a
// preconditioner
GridCgInterface *gcg;
if (vel.is3D())
gcg = new GridCg<ApplyMatrix>(pressure, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak);
else
gcg = new GridCg<ApplyMatrix2D>(
pressure, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak);
vector<Grid<Real> *> matA{&A0, &Ai, &Aj};
if (vel.is3D()) {
matA.push_back(&Ak);
gcg = new GridCg<ApplyMatrix>(pressure, rhs, residual, search, flags, tmp, matA);
}
else {
gcg = new GridCg<ApplyMatrix2D>(pressure, rhs, residual, search, flags, tmp, matA);
}
gcg->setAccuracy(cgAccuracy);
gcg->setUseL2Norm(useL2Norm);

File diff suppressed because it is too large Load Diff

View File

@ -576,8 +576,10 @@ void VICintegration(VortexSheetMesh &mesh,
// prepare CG solver
const int maxIter = (int)(cgMaxIterFac * vel.getSize().max());
vector<Grid<Real> *> matA{&A0, &Ai, &Aj, &Ak};
GridCgInterface *gcg = new GridCg<ApplyMatrix>(
solution, rhs, residual, search, flags, temp1, &A0, &Ai, &Aj, &Ak);
solution, rhs, residual, search, flags, temp1, matA);
gcg->setAccuracy(cgAccuracy);
gcg->setUseL2Norm(true);
gcg->setICPreconditioner(

View File

@ -423,10 +423,15 @@ void cgSolveWE(const FlagGrid &flags,
const int maxIter = (int)(cgMaxIterFac * flags.getSize().max()) * (flags.is3D() ? 1 : 4);
GridCgInterface *gcg;
if (flags.is3D())
gcg = new GridCg<ApplyMatrix>(out, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak);
else
gcg = new GridCg<ApplyMatrix2D>(out, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak);
vector<Grid<Real> *> matA{&A0, &Ai, &Aj};
if (flags.is3D()) {
matA.push_back(&Ak);
gcg = new GridCg<ApplyMatrix>(out, rhs, residual, search, flags, tmp, matA);
}
else {
gcg = new GridCg<ApplyMatrix2D>(out, rhs, residual, search, flags, tmp, matA);
}
gcg->setAccuracy(cgAccuracy);

View File

@ -145,6 +145,7 @@ extern void PbRegister_flipComputeSurfaceNormals();
extern void PbRegister_flipUpdateNeighborRatio();
extern void PbRegister_particleSurfaceTurbulence();
extern void PbRegister_debugCheckParts();
extern void PbRegister_applyViscosity();
extern void PbRegister_markAsFixed();
extern void PbRegister_texcoordInflow();
extern void PbRegister_meshSmokeInflow();
@ -342,6 +343,7 @@ void MantaEnsureRegistration()
PbRegister_flipUpdateNeighborRatio();
PbRegister_particleSurfaceTurbulence();
PbRegister_debugCheckParts();
PbRegister_applyViscosity();
PbRegister_markAsFixed();
PbRegister_texcoordInflow();
PbRegister_meshSmokeInflow();

View File

@ -351,6 +351,10 @@ static bool lookup_property(BL::ID b_id, const string &name, float4 *r_value)
return false;
}
if (prop == NULL) {
return false;
}
PropertyType type = RNA_property_type(prop);
int arraylen = RNA_property_array_length(&ptr, prop);

View File

@ -72,6 +72,7 @@ MANTA::MANTA(int *res, FluidModifierData *fmd)
mUsingFractions = (fds->flags & FLUID_DOMAIN_USE_FRACTIONS) && mUsingLiquid;
mUsingMesh = (fds->flags & FLUID_DOMAIN_USE_MESH) && mUsingLiquid;
mUsingDiffusion = (fds->flags & FLUID_DOMAIN_USE_DIFFUSION) && mUsingLiquid;
mUsingViscosity = (fds->flags & FLUID_DOMAIN_USE_VISCOSITY) && mUsingLiquid;
mUsingMVel = (fds->flags & FLUID_DOMAIN_USE_SPEED_VECTORS) && mUsingLiquid;
mUsingGuiding = (fds->flags & FLUID_DOMAIN_USE_GUIDE);
mUsingDrops = (fds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) && mUsingLiquid;
@ -221,6 +222,10 @@ MANTA::MANTA(int *res, FluidModifierData *fmd)
initSuccess &= initLiquidMesh();
}
if (mUsingViscosity) {
initSuccess &= initLiquidViscosity();
}
if (mUsingDiffusion) {
initSuccess &= initCurvature();
}
@ -440,6 +445,17 @@ bool MANTA::initLiquidMesh(FluidModifierData *fmd)
return runPythonString(pythonCommands);
}
bool MANTA::initLiquidViscosity(FluidModifierData *fmd)
{
vector<string> pythonCommands;
string tmpString = fluid_variables_viscosity + fluid_solver_viscosity + liquid_alloc_viscosity;
string finalString = parseScript(tmpString, fmd);
pythonCommands.push_back(finalString);
mUsingViscosity = true;
return runPythonString(pythonCommands);
}
bool MANTA::initCurvature(FluidModifierData *fmd)
{
std::vector<std::string> pythonCommands;
@ -871,8 +887,10 @@ void MANTA::initializeRNAMap(FluidModifierData *fmd)
mRNAMap["CACHE_DIR"] = cacheDirectory;
mRNAMap["COMPRESSION_OPENVDB"] = vdbCompressionMethod;
mRNAMap["PRECISION_OPENVDB"] = vdbPrecisionHalf;
mRNAMap["CLIP_OPENVDB"] = to_string(fds->clipping);
mRNAMap["CLIP_OPENVDB"] = to_string(fds->clipping);
mRNAMap["PP_PARTICLE_MAXIMUM"] = to_string(fds->sys_particle_maximum);
mRNAMap["USING_VISCOSITY"] = getBooleanString(fds->flags & FLUID_DOMAIN_USE_VISCOSITY);
mRNAMap["VISCOSITY_VALUE"] = to_string(fds->viscosity_value);
/* Fluid object names. */
mRNAMap["NAME_FLAGS"] = FLUID_NAME_FLAGS;
@ -1728,6 +1746,7 @@ bool MANTA::exportLiquidScript(FluidModifierData *fmd)
bool guiding = fds->active_fields & FLUID_DOMAIN_ACTIVE_GUIDE;
bool invel = fds->active_fields & FLUID_DOMAIN_ACTIVE_INVEL;
bool outflow = fds->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW;
bool viscosity = fds->flags & FLUID_DOMAIN_USE_VISCOSITY;
string manta_script;
@ -1742,6 +1761,8 @@ bool MANTA::exportLiquidScript(FluidModifierData *fmd)
manta_script += fluid_variables_particles + liquid_variables_particles;
if (guiding)
manta_script += fluid_variables_guiding;
if (viscosity)
manta_script += fluid_variables_viscosity;
/* Solvers. */
manta_script += header_solvers + fluid_solver;
@ -1751,6 +1772,8 @@ bool MANTA::exportLiquidScript(FluidModifierData *fmd)
manta_script += fluid_solver_particles;
if (guiding)
manta_script += fluid_solver_guiding;
if (viscosity)
manta_script += fluid_solver_viscosity;
/* Grids. */
manta_script += header_grids + fluid_alloc + liquid_alloc;
@ -1768,6 +1791,8 @@ bool MANTA::exportLiquidScript(FluidModifierData *fmd)
manta_script += fluid_alloc_invel;
if (outflow)
manta_script += fluid_alloc_outflow;
if (viscosity)
manta_script += liquid_alloc_viscosity;
/* Domain init. */
manta_script += header_gridinit + liquid_init_phi;

View File

@ -67,6 +67,7 @@ struct MANTA {
bool initColorsHigh(struct FluidModifierData *fmd = nullptr);
bool initLiquid(FluidModifierData *fmd = nullptr);
bool initLiquidMesh(FluidModifierData *fmd = nullptr);
bool initLiquidViscosity(FluidModifierData *fmd = nullptr);
bool initObstacle(FluidModifierData *fmd = nullptr);
bool initCurvature(FluidModifierData *fmd = nullptr);
bool initGuiding(FluidModifierData *fmd = nullptr);
@ -757,6 +758,7 @@ struct MANTA {
bool mUsingNoise;
bool mUsingMesh;
bool mUsingDiffusion;
bool mUsingViscosity;
bool mUsingMVel;
bool mUsingLiquid;
bool mUsingSmoke;

View File

@ -79,6 +79,11 @@ const std::string fluid_solver_guiding =
mantaMsg('Solver guiding')\n\
sg$ID$ = Solver(name='solver_guiding$ID$', gridSize=gs_sg$ID$)\n";
const std::string fluid_solver_viscosity =
"\n\
mantaMsg('Solver viscosity')\n\
sv$ID$ = Solver(name='solver_viscosity$ID$', gridSize=gs_sv$ID$, dim=dim_s$ID$)\n";
//////////////////////////////////////////////////////////////////////
// VARIABLES
//////////////////////////////////////////////////////////////////////
@ -133,7 +138,7 @@ end_frame_s$ID$ = $END_FRAME$\n\
\n\
# Fluid diffusion / viscosity\n\
domainSize_s$ID$ = $FLUID_DOMAIN_SIZE$ # longest domain side in meters\n\
viscosity_s$ID$ = $FLUID_VISCOSITY$ / (domainSize_s$ID$*domainSize_s$ID$) # kinematic viscosity in m^2/s\n\
kinViscosity_s$ID$ = $FLUID_VISCOSITY$ / (domainSize_s$ID$*domainSize_s$ID$) # kinematic viscosity in m^2/s\n\
\n\
# Factors to convert Blender units to Manta units\n\
ratioMetersToRes_s$ID$ = float(domainSize_s$ID$) / float(res_s$ID$) # [meters / cells]\n\
@ -199,6 +204,10 @@ tau_sg$ID$ = 1.0\n\
sigma_sg$ID$ = 0.99/tau_sg$ID$\n\
theta_sg$ID$ = 1.0\n";
const std::string fluid_variables_viscosity =
"\n\
gs_sv$ID$ = vec3($RESX$*2, $RESY$*2, $RESZ$*2)\n";
const std::string fluid_with_obstacle =
"\n\
using_obstacle_s$ID$ = True\n";

View File

@ -40,6 +40,8 @@ radiusFactor_s$ID$ = $PARTICLE_RADIUS$\n\
using_mesh_s$ID$ = $USING_MESH$\n\
using_final_mesh_s$ID$ = $USING_IMPROVED_MESH$\n\
using_fractions_s$ID$ = $USING_FRACTIONS$\n\
using_apic_s$ID$ = $USING_APIC$\n\
using_viscosity_s$ID$ = $USING_VISCOSITY$\n\
fracThreshold_s$ID$ = $FRACTIONS_THRESHOLD$\n\
fracDistance_s$ID$ = $FRACTIONS_DISTANCE$\n\
flipRatio_s$ID$ = $FLIP_RATIO$\n\
@ -51,7 +53,7 @@ smoothenNeg_s$ID$ = $MESH_SMOOTHEN_NEG$\n\
randomness_s$ID$ = $PARTICLE_RANDOMNESS$\n\
surfaceTension_s$ID$ = $LIQUID_SURFACE_TENSION$\n\
maxSysParticles_s$ID$ = $PP_PARTICLE_MAXIMUM$\n\
using_apic_s$ID$ = $USING_APIC$\n";
viscosityValue_s$ID$ = $VISCOSITY_VALUE$\n";
const std::string liquid_variables_particles =
"\n\
@ -135,6 +137,13 @@ liquid_mesh_dict_s$ID$ = { 'lMesh' : mesh_sm$ID$ }\n\
if using_speedvectors_s$ID$:\n\
liquid_meshvel_dict_s$ID$ = { 'lVelMesh' : mVel_mesh$ID$ }\n";
const std::string liquid_alloc_viscosity =
"\n\
# Viscosity grids\n\
volumes_s$ID$ = sv$ID$.create(RealGrid)\n\
viscosity_s$ID$ = s$ID$.create(RealGrid)\n\
viscosity_s$ID$.setConst(viscosityValue_s$ID$)\n";
const std::string liquid_alloc_curvature =
"\n\
mantaMsg('Liquid alloc curvature')\n\
@ -306,7 +315,7 @@ def liquid_step_$ID$():\n\
if using_diffusion_s$ID$:\n\
mantaMsg('Viscosity')\n\
# diffusion param for solve = const * dt / dx^2\n\
alphaV = viscosity_s$ID$ * s$ID$.timestep * float(res_s$ID$*res_s$ID$)\n\
alphaV = kinViscosity_s$ID$ * s$ID$.timestep * float(res_s$ID$*res_s$ID$)\n\
setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=None if using_fractions_s$ID$ else obvel_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$)\n\
cgSolveDiffusion(flags_s$ID$, vel_s$ID$, alphaV)\n\
\n\
@ -315,7 +324,11 @@ def liquid_step_$ID$():\n\
curvature_s$ID$.clamp(-1.0, 1.0)\n\
\n\
setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=None if using_fractions_s$ID$ else obvel_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$)\n\
if using_viscosity_s$ID$:\n\
viscosity_s$ID$.setConst(viscosityValue_s$ID$)\n\
applyViscosity(flags=flags_s$ID$, phi=phi_s$ID$, vel=vel_s$ID$, volumes=volumes_s$ID$, viscosity=viscosity_s$ID$)\n\
\n\
setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=None if using_fractions_s$ID$ else obvel_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$)\n\
if using_guiding_s$ID$:\n\
mantaMsg('Guiding and pressure')\n\
PD_fluid_guiding(vel=vel_s$ID$, velT=velT_s$ID$, flags=flags_s$ID$, phi=phi_s$ID$, curv=curvature_s$ID$, surfTens=surfaceTension_s$ID$, fractions=fractions_s$ID$, weight=weightGuide_s$ID$, blurRadius=beta_sg$ID$, pressure=pressure_s$ID$, tau=tau_sg$ID$, sigma=sigma_sg$ID$, theta=theta_sg$ID$, zeroPressureFixing=domainClosed_s$ID$)\n\

View File

@ -1006,6 +1006,46 @@ class PHYSICS_PT_particles(PhysicButtonsPanel, Panel):
split.operator("fluid.free_particles", text="Free Particles")
class PHYSICS_PT_viscosity(PhysicButtonsPanel, Panel):
bl_label = "Viscosity"
bl_parent_id = 'PHYSICS_PT_liquid'
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
@classmethod
def poll(cls, context):
# Fluid viscosity only enabled for liquids
if not PhysicButtonsPanel.poll_liquid_domain(context):
return False
return (context.engine in cls.COMPAT_ENGINES)
def draw_header(self, context):
md = context.fluid.domain_settings
domain = context.fluid.domain_settings
is_baking_any = domain.is_cache_baking_any
has_baked_any = domain.has_cache_baked_any
self.layout.enabled = not is_baking_any and not has_baked_any
self.layout.prop(md, "use_viscosity", text="")
def draw(self, context):
layout = self.layout
layout.use_property_split = True
domain = context.fluid.domain_settings
layout.active = domain.use_viscosity
is_baking_any = domain.is_cache_baking_any
has_baked_any = domain.has_cache_baked_any
has_baked_data = domain.has_cache_baked_data
flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
flow.enabled = not is_baking_any and not has_baked_any and not has_baked_data
col = flow.column(align=True)
col.prop(domain, "viscosity_value", text="Strength")
class PHYSICS_PT_diffusion(PhysicButtonsPanel, Panel):
bl_label = "Diffusion"
bl_parent_id = 'PHYSICS_PT_liquid'
@ -1470,6 +1510,7 @@ classes = (
PHYSICS_PT_noise,
PHYSICS_PT_fire,
PHYSICS_PT_liquid,
PHYSICS_PT_viscosity,
PHYSICS_PT_diffusion,
PHYSICS_PT_particles,
PHYSICS_PT_mesh,

View File

@ -514,6 +514,7 @@ geometry_node_categories = [
NodeItem("GeometryNodePointDistribute"),
NodeItem("GeometryNodePointInstance"),
NodeItem("GeometryNodePointSeparate"),
NodeItem("GeometryNodeRotatePoints"),
]),
GeometryNodeCategory("GEO_UTILITIES", "Utilities", items=[
NodeItem("ShaderNodeMapRange"),

View File

@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 8
#define BLENDER_FILE_SUBVERSION 9
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file

View File

@ -1356,6 +1356,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_ATTRIBUTE_COLOR_RAMP 1013
#define GEO_NODE_POINT_SEPARATE 1014
#define GEO_NODE_ATTRIBUTE_COMPARE 1015
#define GEO_NODE_ROTATE_POINTS 1016
/** \} */

View File

@ -635,9 +635,6 @@ void BKE_sculpt_sync_face_sets_visibility_to_base_mesh(struct Mesh *mesh);
void BKE_sculpt_sync_face_sets_visibility_to_grids(struct Mesh *mesh,
struct SubdivCCG *subdiv_ccg);
/* Ensures that a Face Set data-layers exists. If it does not, it creates one respecting the
* visibility stored in the vertices of the mesh. If it does, it copies the visibility from the
* mesh to the Face Sets. */
void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(struct Mesh *mesh);
bool BKE_sculptsession_use_pbvh_draw(const struct Object *ob, const struct View3D *v3d);

View File

@ -5011,6 +5011,9 @@ void BKE_fluid_modifier_copy(const struct FluidModifierData *fmd,
tfds->sys_particle_maximum = fds->sys_particle_maximum;
tfds->simulation_method = fds->simulation_method;
/* viscosity options */
tfds->viscosity_value = fds->viscosity_value;
/* diffusion options*/
tfds->surface_tension = fds->surface_tension;
tfds->viscosity_base = fds->viscosity_base;

View File

@ -61,8 +61,24 @@ bool multires_reshape_assign_final_coords_from_ccg(const MultiresReshapeContext
sizeof(float[3]));
if (reshape_level_key.has_mask) {
BLI_assert(grid_element.mask != NULL);
*grid_element.mask = *CCG_grid_elem_mask(&reshape_level_key, ccg_grid, x, y);
/* Assert about a non-NULL `grid_element.mask` may fail here, this code may be called
* from cleanup code during COW evaluation phase by depsgraph (e.g.
* `object_update_from_subsurf_ccg` call in `BKE_object_free_derived_caches`).
*
* `reshape_level_key.has_mask` is ultimately set from MultiRes modifier apply code
* (through `multires_as_ccg` -> `multires_ccg_settings_init`), when object is in sculpt
* mode only, and there is matching loop cdlayer.
*
* `grid_element.mask` is directly set from existing matching loop cdlayer during
* initialization of `MultiresReshapeContext` struct.
*
* Since ccg data is preserved during undos, we may end up with a state where there is no
* mask data in mesh loops' cdlayer, while ccg's `has_mask` is still set to true.
*/
// BLI_assert(grid_element.mask != NULL);
if (grid_element.mask != NULL) {
*grid_element.mask = *CCG_grid_elem_mask(&reshape_level_key, ccg_grid, x, y);
}
}
}
}

View File

@ -4744,6 +4744,7 @@ static void registerGeometryNodes(void)
register_node_type_geo_join_geometry();
register_node_type_geo_attribute_mix();
register_node_type_geo_attribute_color_ramp();
register_node_type_geo_rotate_points();
}
static void registerFunctionNodes(void)

View File

@ -1596,7 +1596,7 @@ static void sculpt_update_object(Depsgraph *depsgraph,
Scene *scene = DEG_get_input_scene(depsgraph);
Sculpt *sd = scene->toolsettings->sculpt;
SculptSession *ss = ob->sculpt;
Mesh *me = BKE_object_get_original_mesh(ob);
const Mesh *me = BKE_object_get_original_mesh(ob);
MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
const bool use_face_sets = (ob->mode & OB_MODE_SCULPT) != 0;
@ -1612,20 +1612,13 @@ static void sculpt_update_object(Depsgraph *depsgraph,
if (need_mask) {
if (mmd == NULL) {
if (!CustomData_has_layer(&me->vdata, CD_PAINT_MASK)) {
BKE_sculpt_mask_layers_ensure(ob, NULL);
}
BLI_assert(CustomData_has_layer(&me->vdata, CD_PAINT_MASK));
}
else {
if (!CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK)) {
BKE_sculpt_mask_layers_ensure(ob, mmd);
}
BLI_assert(CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK));
}
}
/* tessfaces aren't used and will become invalid */
BKE_mesh_tessface_clear(me);
ss->shapekey_active = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL;
/* NOTE: Weight pPaint require mesh info for loop lookup, but it never uses multires code path,
@ -1660,12 +1653,7 @@ static void sculpt_update_object(Depsgraph *depsgraph,
/* Sculpt Face Sets. */
if (use_face_sets) {
if (!CustomData_has_layer(&me->pdata, CD_SCULPT_FACE_SETS)) {
/* By checking here if the data-layer already exist this avoids copying the visibility from
* the mesh and looping over all vertices on every sculpt editing operation, using this
* function only the first time the Face Sets data-layer needs to be created. */
BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(me);
}
BLI_assert(CustomData_has_layer(&me->pdata, CD_SCULPT_FACE_SETS));
ss->face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS);
}
else {
@ -1928,6 +1916,10 @@ static bool check_sculpt_object_deformed(Object *object, const bool for_construc
return deformed;
}
/**
* Ensures that a Face Set data-layers exists. If it does not, it creates one respecting the
* visibility stored in the vertices of the mesh. If it does, it copies the visibility from the
* mesh to the Face Sets. */
void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(Mesh *mesh)
{
const int face_sets_default_visible_id = 1;

View File

@ -1430,18 +1430,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
/**
* Versioning code until next subversion bump goes here.
*
* \note Be sure to check when bumping the version:
* - "versioning_userdef.c", #blo_do_versions_userdef
* - "versioning_userdef.c", #do_versions_theme
*
* \note Keep this message at the bottom of the function.
*/
{
/* Keep this block, even when empty. */
if (!MAIN_VERSION_ATLEAST(bmain, 292, 9)) {
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_GEOMETRY) {
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
@ -1474,5 +1463,32 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
/* Ensure that new viscosity strength field is initialized correctly. */
if (!DNA_struct_elem_find(fd->filesdna, "FluidModifierData", "float", "viscosity_value")) {
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type == eModifierType_Fluid) {
FluidModifierData *fmd = (FluidModifierData *)md;
if (fmd->domain != NULL) {
fmd->domain->viscosity_value = 0.05;
}
}
}
}
}
}
/**
* Versioning code until next subversion bump goes here.
*
* \note Be sure to check when bumping the version:
* - "versioning_userdef.c", #blo_do_versions_userdef
* - "versioning_userdef.c", #do_versions_theme
*
* \note Keep this message at the bottom of the function.
*/
{
/* Keep this block, even when empty. */
}
}

View File

@ -820,6 +820,12 @@ void blo_do_versions_userdef(UserDef *userdef)
userdef->uiflag &= ~USER_UIFLAG_UNUSED_3;
}
if (!USER_VERSION_ATLEAST(292, 9)) {
if (BLI_listbase_is_empty(&userdef->asset_libraries)) {
BKE_preferences_asset_library_default_add(userdef);
}
}
/**
* Versioning code until next subversion bump goes here.
*
@ -831,9 +837,6 @@ void blo_do_versions_userdef(UserDef *userdef)
*/
{
/* Keep this block, even when empty. */
if (BLI_listbase_is_empty(&userdef->asset_libraries)) {
BKE_preferences_asset_library_default_add(userdef);
}
}
LISTBASE_FOREACH (bTheme *, btheme, &userdef->themes) {

View File

@ -26,7 +26,7 @@ ExposureNode::ExposureNode(bNode *editorNode) : Node(editorNode)
}
void ExposureNode::convertToOperations(NodeConverter &converter,
const CompositorContext & /*context*/) const
const CompositorContext & /*context*/) const
{
ExposureOperation *operation = new ExposureOperation();
converter.addOperation(operation);

View File

@ -633,6 +633,10 @@ static bool drw_uniform_property_lookup(ID *id, const char *name, float r_data[4
return false;
}
if (prop == NULL) {
return false;
}
PropertyType type = RNA_property_type(prop);
int arraylen = RNA_property_array_length(&ptr, prop);

View File

@ -52,9 +52,6 @@ void ED_spacedata_id_remap(struct ScrArea *area,
struct ID *old_id,
struct ID *new_id);
void ED_OT_lib_id_load_custom_preview(struct wmOperatorType *ot);
void ED_OT_lib_id_generate_preview(struct wmOperatorType *ot);
void ED_operatortypes_edutils(void);
/* ************** XXX OLD CRUFT WARNING ************* */

View File

@ -1626,10 +1626,10 @@ static uiButExtraOpIcon *ui_but_extra_operator_icon_add_ptr(uiBut *but,
extra_op_icon->icon = (BIFIconID)icon;
extra_op_icon->optype_params = MEM_callocN(sizeof(*extra_op_icon->optype_params),
"uiButExtraOpIcon.optype_hook");
"uiButExtraOpIcon.optype_params");
extra_op_icon->optype_params->optype = optype;
extra_op_icon->optype_params->opptr = MEM_callocN(sizeof(*extra_op_icon->optype_params->opptr),
"uiButExtraOpIcon.optype_hook.opptr");
"uiButExtraOpIcon.optype_params.opptr");
WM_operator_properties_create_ptr(extra_op_icon->optype_params->opptr,
extra_op_icon->optype_params->optype);
extra_op_icon->optype_params->opcontext = opcontext;

View File

@ -1392,7 +1392,7 @@ static void template_id_name_button(
UI_but_extra_operator_icon_add(but, template_ui->unlink_op, WM_OP_INVOKE_DEFAULT, ICON_X);
}
else if (!never_unlink) {
UI_but_extra_operator_icon_add(but, "ED_OT_lib_unlink", WM_OP_INVOKE_DEFAULT, ICON_X);
UI_but_extra_operator_icon_add(but, "ED_OT_lib_id_unlink", WM_OP_INVOKE_DEFAULT, ICON_X);
}
}
@ -1401,7 +1401,7 @@ static void template_id_name_button(
if (add_extra_fake_user_icon && id->lib == NULL &&
!(ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB, ID_WS))) {
UI_but_extra_operator_icon_add(but,
"ED_OT_lib_fake_user_toggle",
"ED_OT_lib_id_fake_user_toggle",
WM_OP_INVOKE_DEFAULT,
ID_FAKE_USERS(id) ? ICON_FAKE_USER_ON : ICON_FAKE_USER_OFF);
}

View File

@ -3138,6 +3138,8 @@ static int screen_maximize_area_exec(bContext *C, wmOperator *op)
ScrArea *area = NULL;
const bool hide_panels = RNA_boolean_get(op->ptr, "use_hide_panels");
BLI_assert(!screen->temp);
/* search current screen for 'fullscreen' areas */
/* prevents restoring info header, when mouse is over it */
LISTBASE_FOREACH (ScrArea *, area_iter, &screen->areabase) {
@ -3169,11 +3171,14 @@ static int screen_maximize_area_exec(bContext *C, wmOperator *op)
static bool screen_maximize_area_poll(bContext *C)
{
const wmWindow *win = CTX_wm_window(C);
const bScreen *screen = CTX_wm_screen(C);
const ScrArea *area = CTX_wm_area(C);
return ED_operator_areaactive(C) &&
/* Don't allow maximizing global areas but allow minimizing from them. */
((screen->state != SCREENNORMAL) || !ED_area_is_global(area));
((screen->state != SCREENNORMAL) || !ED_area_is_global(area)) &&
/* Don't change temporary screens. */
!WM_window_is_temp_screen(win);
}
static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
@ -5501,16 +5506,6 @@ void ED_operatortypes_screen(void)
/* new/delete */
WM_operatortype_append(SCREEN_OT_new);
WM_operatortype_append(SCREEN_OT_delete);
/* tools shared by more space types */
WM_operatortype_append(ED_OT_undo);
WM_operatortype_append(ED_OT_undo_push);
WM_operatortype_append(ED_OT_redo);
WM_operatortype_append(ED_OT_undo_redo);
WM_operatortype_append(ED_OT_undo_history);
WM_operatortype_append(ED_OT_lib_id_load_custom_preview);
WM_operatortype_append(ED_OT_lib_id_generate_preview);
}
/** \} */

View File

@ -1190,25 +1190,6 @@ void SCULPT_floodfill_free(SculptFloodFill *flood)
*
* \{ */
/* Check if there are any active modifiers in stack.
* Used for flushing updates at enter/exit sculpt mode. */
static bool sculpt_has_active_modifiers(Scene *scene, Object *ob)
{
ModifierData *md;
VirtualModifierData virtualModifierData;
md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
/* Exception for shape keys because we can edit those. */
for (; md; md = md->next) {
if (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
return true;
}
}
return false;
}
static bool sculpt_tool_needs_original(const char sculpt_tool)
{
return ELEM(sculpt_tool,
@ -8655,7 +8636,7 @@ static void sculpt_init_session(Depsgraph *depsgraph, Scene *scene, Object *ob)
/* Here we can detect geometry that was just added to Sculpt Mode as it has the
* SCULPT_FACE_SET_NONE assigned, so we can create a new Face Set for it. */
/* In sculpt mode all geometry that is assigned to SCULPT_FACE_SET_NONE is considered as not
* initialized, which is used is some operators that modify the mesh topology to preform certain
* initialized, which is used is some operators that modify the mesh topology to perform certain
* actions in the new polys. After these operations are finished, all polys should have a valid
* face set ID assigned (different from SCULPT_FACE_SET_NONE) to manage their visibility
* correctly. */
@ -8669,23 +8650,6 @@ static void sculpt_init_session(Depsgraph *depsgraph, Scene *scene, Object *ob)
ss->face_sets[i] = new_face_set;
}
}
/* Update the Face Sets visibility with the vertex visibility changes that may have been done
* outside Sculpt Mode */
Mesh *mesh = ob->data;
BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(mesh);
}
static int ed_object_sculptmode_flush_recalc_flag(Scene *scene,
Object *ob,
MultiresModifierData *mmd)
{
int flush_recalc = 0;
/* Multires in sculpt mode could have different from object mode subdivision level. */
flush_recalc |= mmd && mmd->sculptlvl != mmd->lvl;
/* If object has got active modifiers, its dm could be different in sculpt mode. */
flush_recalc |= sculpt_has_active_modifiers(scene, ob);
return flush_recalc;
}
void ED_object_sculptmode_enter_ex(Main *bmain,
@ -8703,13 +8667,6 @@ void ED_object_sculptmode_enter_ex(Main *bmain,
MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd);
if (flush_recalc) {
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
}
/* Create sculpt mode session data. */
if (ob->sculpt) {
BKE_sculptsession_free(ob);
@ -8718,14 +8675,30 @@ void ED_object_sculptmode_enter_ex(Main *bmain,
/* Copy the current mesh visibility to the Face Sets. */
BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(me);
sculpt_init_session(depsgraph, scene, ob);
/* Mask layer is required for Multires. */
BKE_sculpt_mask_layers_ensure(ob, mmd);
/* Mask layer is required. */
if (mmd) {
/* XXX, we could attempt to support adding mask data mid-sculpt mode (with multi-res)
* but this ends up being quite tricky (and slow). */
BKE_sculpt_mask_layers_ensure(ob, mmd);
}
/* Tessfaces aren't used and will become invalid. */
BKE_mesh_tessface_clear(me);
/* We always need to flush updates from depsgraph here, since at the very least
* `BKE_sculpt_face_sets_ensure_from_base_mesh_visibility()` will have updated some data layer of
* the mesh.
*
* All known potential sources of updates:
* - Addition of, or changes to, the `CD_SCULPT_FACE_SETS` data layer
* (`BKE_sculpt_face_sets_ensure_from_base_mesh_visibility`).
* - Addition of a `CD_PAINT_MASK` data layer (`BKE_sculpt_mask_layers_ensure`).
* - Object has any active modifier (modifier stack can be different in Sculpt mode).
* - Multires:
* + Differences of subdiv levels between sculpt and object modes
* (`mmd->sculptlvl != mmd->lvl`).
* + Addition of a `CD_GRID_PAINT_MASK` data layer (`BKE_sculpt_mask_layers_ensure`).
*/
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
sculpt_init_session(depsgraph, scene, ob);
if (!(fabsf(ob->scale[0] - ob->scale[1]) < 1e-4f &&
fabsf(ob->scale[1] - ob->scale[2]) < 1e-4f)) {

View File

@ -921,7 +921,7 @@ SculptUndoNode *SCULPT_undo_get_first_node()
return usculpt->nodes.first;
}
static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh, SculptUndoNode *unode)
static size_t sculpt_undo_alloc_and_store_hidden(PBVH *pbvh, SculptUndoNode *unode)
{
PBVHNode *node = unode->node;
BLI_bitmap **grid_hidden = BKE_pbvh_grid_hidden(pbvh);
@ -929,28 +929,34 @@ static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh, SculptUndoNode *unode
int *grid_indices, totgrid;
BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, NULL, NULL, NULL);
unode->grid_hidden = MEM_callocN(sizeof(*unode->grid_hidden) * totgrid, "unode->grid_hidden");
size_t alloc_size = sizeof(*unode->grid_hidden) * (size_t)totgrid;
unode->grid_hidden = MEM_callocN(alloc_size, "unode->grid_hidden");
for (int i = 0; i < totgrid; i++) {
if (grid_hidden[grid_indices[i]]) {
unode->grid_hidden[i] = MEM_dupallocN(grid_hidden[grid_indices[i]]);
alloc_size += MEM_allocN_len(unode->grid_hidden[i]);
}
else {
unode->grid_hidden[i] = NULL;
}
}
return alloc_size;
}
/* Allocate node and initialize its default fields specific for the given undo type.
* Will also add the node to the list in the undo step. */
static SculptUndoNode *sculpt_undo_alloc_node_type(Object *object, SculptUndoType type)
{
SculptUndoNode *unode = MEM_callocN(sizeof(SculptUndoNode), "SculptUndoNode");
const size_t alloc_size = sizeof(SculptUndoNode);
SculptUndoNode *unode = MEM_callocN(alloc_size, "SculptUndoNode");
BLI_strncpy(unode->idname, object->id.name, sizeof(unode->idname));
unode->type = type;
UndoSculpt *usculpt = sculpt_undo_get_nodes();
BLI_addtail(&usculpt->nodes, unode);
usculpt->undo_size += alloc_size;
return unode;
}
@ -975,7 +981,12 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
{
UndoSculpt *usculpt = sculpt_undo_get_nodes();
SculptSession *ss = ob->sculpt;
int totvert, allvert, totgrid, maxgrid, gridsize, *grids;
int totvert = 0;
int allvert = 0;
int totgrid = 0;
int maxgrid = 0;
int gridsize = 0;
int *grids = NULL;
SculptUndoNode *unode = sculpt_undo_alloc_node_type(ob, type);
unode->node = node;
@ -986,39 +997,43 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
unode->totvert = totvert;
}
else {
maxgrid = 0;
}
/* General TODO, fix count_alloc. */
switch (type) {
case SCULPT_UNDO_COORDS:
unode->co = MEM_callocN(sizeof(float[3]) * allvert, "SculptUndoNode.co");
unode->no = MEM_callocN(sizeof(short[3]) * allvert, "SculptUndoNode.no");
case SCULPT_UNDO_COORDS: {
size_t alloc_size = sizeof(*unode->co) * (size_t)allvert;
unode->co = MEM_callocN(alloc_size, "SculptUndoNode.co");
usculpt->undo_size += alloc_size;
usculpt->undo_size = (sizeof(float[3]) + sizeof(short[3]) + sizeof(int)) * allvert;
/* FIXME: Should explain why this is allocated here, to be freed in
* `SCULPT_undo_push_end_ex()`? */
alloc_size = sizeof(*unode->no) * (size_t)allvert;
unode->no = MEM_callocN(alloc_size, "SculptUndoNode.no");
usculpt->undo_size += alloc_size;
break;
case SCULPT_UNDO_HIDDEN:
}
case SCULPT_UNDO_HIDDEN: {
if (maxgrid) {
sculpt_undo_alloc_and_store_hidden(ss->pbvh, unode);
usculpt->undo_size += sculpt_undo_alloc_and_store_hidden(ss->pbvh, unode);
}
else {
unode->vert_hidden = BLI_BITMAP_NEW(allvert, "SculptUndoNode.vert_hidden");
usculpt->undo_size += BLI_BITMAP_SIZE(allvert);
}
break;
case SCULPT_UNDO_MASK:
unode->mask = MEM_callocN(sizeof(float) * allvert, "SculptUndoNode.mask");
usculpt->undo_size += (sizeof(float) * sizeof(int)) * allvert;
}
case SCULPT_UNDO_MASK: {
const size_t alloc_size = sizeof(*unode->mask) * (size_t)allvert;
unode->mask = MEM_callocN(alloc_size, "SculptUndoNode.mask");
usculpt->undo_size += alloc_size;
break;
case SCULPT_UNDO_COLOR:
unode->col = MEM_callocN(sizeof(MPropCol) * allvert, "SculptUndoNode.col");
usculpt->undo_size += (sizeof(MPropCol) * sizeof(int)) * allvert;
}
case SCULPT_UNDO_COLOR: {
const size_t alloc_size = sizeof(*unode->col) * (size_t)allvert;
unode->col = MEM_callocN(alloc_size, "SculptUndoNode.col");
usculpt->undo_size += alloc_size;
break;
}
case SCULPT_UNDO_DYNTOPO_BEGIN:
case SCULPT_UNDO_DYNTOPO_END:
case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
@ -1033,16 +1048,24 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
unode->maxgrid = maxgrid;
unode->totgrid = totgrid;
unode->gridsize = gridsize;
unode->grids = MEM_callocN(sizeof(int) * totgrid, "SculptUndoNode.grids");
const size_t alloc_size = sizeof(*unode->grids) * (size_t)totgrid;
unode->grids = MEM_callocN(alloc_size, "SculptUndoNode.grids");
usculpt->undo_size += alloc_size;
}
else {
/* Regular mesh. */
unode->maxvert = ss->totvert;
unode->index = MEM_callocN(sizeof(int) * allvert, "SculptUndoNode.index");
const size_t alloc_size = sizeof(*unode->index) * (size_t)allvert;
unode->index = MEM_callocN(alloc_size, "SculptUndoNode.index");
usculpt->undo_size += alloc_size;
}
if (ss->deform_modifiers_active) {
unode->orig_co = MEM_callocN(allvert * sizeof(*unode->orig_co), "undoSculpt orig_cos");
const size_t alloc_size = sizeof(*unode->orig_co) * (size_t)allvert;
unode->orig_co = MEM_callocN(alloc_size, "undoSculpt orig_cos");
usculpt->undo_size += alloc_size;
}
return unode;
@ -1364,6 +1387,7 @@ void SCULPT_undo_push_end_ex(const bool use_nested_undo)
/* We don't need normals in the undo stack. */
for (unode = usculpt->nodes.first; unode; unode = unode->next) {
if (unode->no) {
usculpt->undo_size -= MEM_allocN_len(unode->no);
MEM_freeN(unode->no);
unode->no = NULL;
}

View File

@ -104,17 +104,11 @@ void ED_clip_buttons_register(ARegionType *art)
void uiTemplateMovieClip(
uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, bool compact)
{
PropertyRNA *prop;
PointerRNA clipptr;
MovieClip *clip;
uiLayout *row, *split;
uiBlock *block;
if (!ptr->data) {
return;
}
prop = RNA_struct_find_property(ptr, propname);
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
if (!prop) {
printf(
"%s: property not found: %s.%s\n", __func__, RNA_struct_identifier(ptr->type), propname);
@ -129,8 +123,8 @@ void uiTemplateMovieClip(
return;
}
clipptr = RNA_property_pointer_get(ptr, prop);
clip = clipptr.data;
PointerRNA clipptr = RNA_property_pointer_get(ptr, prop);
MovieClip *clip = clipptr.data;
uiLayoutSetContextPointer(layout, "edit_movieclip", &clipptr);
@ -149,20 +143,18 @@ void uiTemplateMovieClip(
}
if (clip) {
uiLayout *col;
row = uiLayoutRow(layout, false);
block = uiLayoutGetBlock(row);
uiLayout *row = uiLayoutRow(layout, false);
uiBlock *block = uiLayoutGetBlock(row);
uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("File Path:"), 0, 19, 145, 19, NULL, 0, 0, 0, 0, "");
row = uiLayoutRow(layout, false);
split = uiLayoutSplit(row, 0.0f, false);
uiLayout *split = uiLayoutSplit(row, 0.0f, false);
row = uiLayoutRow(split, true);
uiItemR(row, &clipptr, "filepath", 0, "", ICON_NONE);
uiItemO(row, "", ICON_FILE_REFRESH, "clip.reload");
col = uiLayoutColumn(layout, false);
uiLayout *col = uiLayoutColumn(layout, false);
uiTemplateColorspaceSettings(col, &clipptr, "colorspace_settings");
}
}
@ -171,17 +163,11 @@ void uiTemplateMovieClip(
void uiTemplateTrack(uiLayout *layout, PointerRNA *ptr, const char *propname)
{
PropertyRNA *prop;
PointerRNA scopesptr;
uiBlock *block;
uiLayout *col;
MovieClipScopes *scopes;
if (!ptr->data) {
return;
}
prop = RNA_struct_find_property(ptr, propname);
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
if (!prop) {
printf(
"%s: property not found: %s.%s\n", __func__, RNA_struct_identifier(ptr->type), propname);
@ -196,8 +182,8 @@ void uiTemplateTrack(uiLayout *layout, PointerRNA *ptr, const char *propname)
return;
}
scopesptr = RNA_property_pointer_get(ptr, prop);
scopes = (MovieClipScopes *)scopesptr.data;
PointerRNA scopesptr = RNA_property_pointer_get(ptr, prop);
MovieClipScopes *scopes = (MovieClipScopes *)scopesptr.data;
if (scopes->track_preview_height < UI_UNIT_Y) {
scopes->track_preview_height = UI_UNIT_Y;
@ -206,8 +192,8 @@ void uiTemplateTrack(uiLayout *layout, PointerRNA *ptr, const char *propname)
scopes->track_preview_height = UI_UNIT_Y * 20;
}
col = uiLayoutColumn(layout, true);
block = uiLayoutGetBlock(col);
uiLayout *col = uiLayoutColumn(layout, true);
uiBlock *block = uiLayoutGetBlock(col);
uiDefBut(block,
UI_BTYPE_TRACK_PREVIEW,
@ -319,8 +305,6 @@ static void marker_block_handler(bContext *C, void *arg_cb, int event)
}
else if (event == B_MARKER_PAT_DIM) {
float dim[2], pat_dim[2], pat_min[2], pat_max[2];
float scale_x, scale_y;
int a;
BKE_tracking_marker_pattern_minmax(cb->marker, pat_min, pat_max);
@ -329,10 +313,10 @@ static void marker_block_handler(bContext *C, void *arg_cb, int event)
dim[0] = cb->marker_pat[0] / width;
dim[1] = cb->marker_pat[1] / height;
scale_x = dim[0] / pat_dim[0];
scale_y = dim[1] / pat_dim[1];
float scale_x = dim[0] / pat_dim[0];
float scale_y = dim[1] / pat_dim[1];
for (a = 0; a < 4; a++) {
for (int a = 0; a < 4; a++) {
cb->marker->pattern_corners[a][0] *= scale_x;
cb->marker->pattern_corners[a][1] *= scale_y;
}
@ -415,23 +399,11 @@ void uiTemplateMarker(uiLayout *layout,
PointerRNA *trackptr,
bool compact)
{
PropertyRNA *prop;
uiBlock *block;
uiBut *bt;
PointerRNA clipptr;
MovieClip *clip;
MovieClipUser *user;
MovieTrackingTrack *track;
MovieTrackingMarker *marker;
MarkerUpdateCb *cb;
const char *tip;
float pat_min[2], pat_max[2];
if (!ptr->data) {
return;
}
prop = RNA_struct_find_property(ptr, propname);
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
if (!prop) {
printf(
"%s: property not found: %s.%s\n", __func__, RNA_struct_identifier(ptr->type), propname);
@ -446,15 +418,15 @@ void uiTemplateMarker(uiLayout *layout,
return;
}
clipptr = RNA_property_pointer_get(ptr, prop);
clip = (MovieClip *)clipptr.data;
user = userptr->data;
track = trackptr->data;
PointerRNA clipptr = RNA_property_pointer_get(ptr, prop);
MovieClip *clip = (MovieClip *)clipptr.data;
MovieClipUser *user = userptr->data;
MovieTrackingTrack *track = trackptr->data;
int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr);
marker = BKE_tracking_marker_get(track, clip_framenr);
MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_framenr);
cb = MEM_callocN(sizeof(MarkerUpdateCb), "uiTemplateMarker update_cb");
MarkerUpdateCb *cb = MEM_callocN(sizeof(MarkerUpdateCb), "uiTemplateMarker update_cb");
cb->compact = compact;
cb->clip = clip;
cb->user = user;
@ -464,7 +436,8 @@ void uiTemplateMarker(uiLayout *layout,
cb->framenr = user->framenr;
if (compact) {
block = uiLayoutGetBlock(layout);
const char *tip;
uiBlock *block = uiLayoutGetBlock(layout);
if (cb->marker_flag & MARKER_DISABLED) {
tip = TIP_("Marker is disabled at current frame");
@ -473,34 +446,32 @@ void uiTemplateMarker(uiLayout *layout,
tip = TIP_("Marker is enabled at current frame");
}
bt = uiDefIconButBitI(block,
UI_BTYPE_TOGGLE_N,
MARKER_DISABLED,
0,
ICON_HIDE_OFF,
0,
0,
UI_UNIT_X,
UI_UNIT_Y,
&cb->marker_flag,
0,
0,
1,
0,
tip);
uiBut *bt = uiDefIconButBitI(block,
UI_BTYPE_TOGGLE_N,
MARKER_DISABLED,
0,
ICON_HIDE_OFF,
0,
0,
UI_UNIT_X,
UI_UNIT_Y,
&cb->marker_flag,
0,
0,
1,
0,
tip);
UI_but_funcN_set(bt, marker_update_cb, cb, NULL);
UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE);
}
else {
int width, height, step, digits;
float pat_dim[2], search_dim[2], search_pos[2];
uiLayout *col;
int width, height;
BKE_movieclip_get_size(clip, user, &width, &height);
if (track->flag & TRACK_LOCKED) {
uiLayoutSetActive(layout, false);
block = uiLayoutAbsoluteBlock(layout);
uiBlock *block = uiLayoutAbsoluteBlock(layout);
uiDefBut(block,
UI_BTYPE_LABEL,
0,
@ -519,8 +490,8 @@ void uiTemplateMarker(uiLayout *layout,
return;
}
step = 100;
digits = 2;
float pat_min[2], pat_max[2];
float pat_dim[2], search_dim[2], search_pos[2];
BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);
@ -538,10 +509,14 @@ void uiTemplateMarker(uiLayout *layout,
cb->marker_flag = marker->flag;
block = uiLayoutAbsoluteBlock(layout);
uiBlock *block = uiLayoutAbsoluteBlock(layout);
UI_block_func_handle_set(block, marker_block_handler, cb);
UI_block_funcN_set(block, marker_update_cb, cb, NULL);
const char *tip;
int step = 100;
int digits = 2;
if (cb->marker_flag & MARKER_DISABLED) {
tip = TIP_("Marker is disabled at current frame");
}
@ -565,7 +540,7 @@ void uiTemplateMarker(uiLayout *layout,
0,
tip);
col = uiLayoutColumn(layout, true);
uiLayout *col = uiLayoutColumn(layout, true);
uiLayoutSetActive(col, (cb->marker_flag & MARKER_DISABLED) == 0);
block = uiLayoutAbsoluteBlock(col);
@ -585,20 +560,20 @@ void uiTemplateMarker(uiLayout *layout,
0,
0,
"");
bt = uiDefButF(block,
UI_BTYPE_NUM,
B_MARKER_POS,
IFACE_("X:"),
0.5 * UI_UNIT_X,
9 * UI_UNIT_Y,
7.25 * UI_UNIT_X,
UI_UNIT_Y,
&cb->marker_pos[0],
-10 * width,
10.0 * width,
0,
0,
TIP_("X-position of marker at frame in screen coordinates"));
uiBut *bt = uiDefButF(block,
UI_BTYPE_NUM,
B_MARKER_POS,
IFACE_("X:"),
0.5 * UI_UNIT_X,
9 * UI_UNIT_Y,
7.25 * UI_UNIT_X,
UI_UNIT_Y,
&cb->marker_pos[0],
-10 * width,
10.0 * width,
0,
0,
TIP_("X-position of marker at frame in screen coordinates"));
UI_but_number_step_size_set(bt, step);
UI_but_number_precision_set(bt, digits);
bt = uiDefButF(block,
@ -802,21 +777,11 @@ void uiTemplateMovieclipInformation(uiLayout *layout,
const char *propname,
PointerRNA *userptr)
{
PropertyRNA *prop;
PointerRNA clipptr;
MovieClip *clip;
MovieClipUser *user;
uiLayout *col;
char str[1024];
int width, height, framenr;
ImBuf *ibuf;
size_t ofs = 0;
if (!ptr->data) {
return;
}
prop = RNA_struct_find_property(ptr, propname);
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
if (!prop) {
printf(
"%s: property not found: %s.%s\n", __func__, RNA_struct_identifier(ptr->type), propname);
@ -831,17 +796,21 @@ void uiTemplateMovieclipInformation(uiLayout *layout,
return;
}
clipptr = RNA_property_pointer_get(ptr, prop);
clip = (MovieClip *)clipptr.data;
user = userptr->data;
PointerRNA clipptr = RNA_property_pointer_get(ptr, prop);
MovieClip *clip = (MovieClip *)clipptr.data;
MovieClipUser *user = userptr->data;
col = uiLayoutColumn(layout, false);
uiLayout *col = uiLayoutColumn(layout, false);
uiLayoutSetAlignment(col, UI_LAYOUT_ALIGN_RIGHT);
ibuf = BKE_movieclip_get_ibuf_flag(clip, user, clip->flag, MOVIECLIP_CACHE_SKIP);
ImBuf *ibuf = BKE_movieclip_get_ibuf_flag(clip, user, clip->flag, MOVIECLIP_CACHE_SKIP);
int width, height;
/* Display frame dimensions, channels number and byffer type. */
BKE_movieclip_get_size(clip, user, &width, &height);
char str[1024];
size_t ofs = 0;
ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, TIP_("%d x %d"), width, height);
if (ibuf) {
@ -882,7 +851,7 @@ void uiTemplateMovieclipInformation(uiLayout *layout,
uiItemL(col, str, ICON_NONE);
/* Display current frame number. */
framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr);
int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr);
if (framenr <= clip->len) {
BLI_snprintf(str, sizeof(str), TIP_("Frame: %d / %d"), framenr, clip->len);
}

View File

@ -1142,7 +1142,9 @@ void ED_fileselect_exit(wmWindowManager *wm, Scene *owner_scene, SpaceFile *sfil
return;
}
if (sfile->op) {
wmWindow *temp_win = WM_window_is_temp_screen(wm->winactive) ? wm->winactive : NULL;
wmWindow *temp_win = (wm->winactive && WM_window_is_temp_screen(wm->winactive)) ?
wm->winactive :
NULL;
if (temp_win) {
int win_size[2];
bool is_maximized;

View File

@ -3260,6 +3260,25 @@ static void node_geometry_buts_attribute_color_ramp(uiLayout *layout,
uiTemplateColorRamp(layout, ptr, "color_ramp", 0);
}
static void node_geometry_buts_rotate_points(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
NodeGeometryRotatePoints *storage = (NodeGeometryRotatePoints *)((bNode *)ptr->data)->storage;
uiItemR(layout, ptr, "type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
uiItemR(layout, ptr, "space", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
uiLayout *col = uiLayoutColumn(layout, false);
if (storage->type == GEO_NODE_ROTATE_POINTS_TYPE_AXIS_ANGLE) {
uiItemR(col, ptr, "input_type_axis", DEFAULT_FLAGS, IFACE_("Axis"), ICON_NONE);
uiItemR(col, ptr, "input_type_angle", DEFAULT_FLAGS, IFACE_("Angle"), ICON_NONE);
}
else {
uiItemR(col, ptr, "input_type_rotation", DEFAULT_FLAGS, IFACE_("Rotation"), ICON_NONE);
}
}
static void node_geometry_set_butfunc(bNodeType *ntype)
{
switch (ntype->type) {
@ -3296,6 +3315,9 @@ static void node_geometry_set_butfunc(bNodeType *ntype)
case GEO_NODE_ATTRIBUTE_COLOR_RAMP:
ntype->draw_buttons = node_geometry_buts_attribute_color_ramp;
break;
case GEO_NODE_ROTATE_POINTS:
ntype->draw_buttons = node_geometry_buts_rotate_points;
break;
}
}

View File

@ -29,50 +29,34 @@
#include "DNA_armature_types.h"
#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "DNA_packedFile_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "BLI_fileops.h"
#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_icons.h"
#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_multires.h"
#include "BKE_object.h"
#include "BKE_packedFile.h"
#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_screen.h"
#include "BKE_undo_system.h"
#include "BKE_workspace.h"
#include "DEG_depsgraph.h"
#include "ED_armature.h"
#include "ED_image.h"
#include "ED_mesh.h"
#include "ED_node.h"
#include "ED_object.h"
#include "ED_outliner.h"
#include "ED_paint.h"
#include "ED_render.h"
#include "ED_space_api.h"
#include "ED_util.h"
#include "GPU_immediate.h"
#include "GPU_state.h"
#include "UI_interface.h"
#include "UI_resources.h"
@ -484,104 +468,3 @@ void ED_spacedata_id_remap(struct ScrArea *area, struct SpaceLink *sl, ID *old_i
st->id_remap(area, sl, old_id, new_id);
}
}
static bool lib_id_preview_editing_poll(bContext *C)
{
const PointerRNA idptr = CTX_data_pointer_get(C, "id");
BLI_assert(!idptr.data || RNA_struct_is_ID(idptr.type));
const ID *id = idptr.data;
if (!id) {
return false;
}
if (ID_IS_LINKED(id)) {
CTX_wm_operator_poll_msg_set(C, TIP_("Can't edit external library data"));
return false;
}
if (ID_IS_OVERRIDE_LIBRARY(id)) {
CTX_wm_operator_poll_msg_set(C, TIP_("Can't edit previews of overridden library data"));
return false;
}
if (!BKE_previewimg_id_get_p(id)) {
CTX_wm_operator_poll_msg_set(C, TIP_("Data-block does not support previews"));
return false;
}
return true;
}
static int lib_id_load_custom_preview_exec(bContext *C, wmOperator *op)
{
char path[FILE_MAX];
RNA_string_get(op->ptr, "filepath", path);
if (!BLI_is_file(path)) {
BKE_reportf(op->reports, RPT_ERROR, "File not found '%s'", path);
return OPERATOR_CANCELLED;
}
PointerRNA idptr = CTX_data_pointer_get(C, "id");
ID *id = idptr.data;
BKE_previewimg_id_custom_set(id, path);
WM_event_add_notifier(C, NC_ASSET, NULL);
return OPERATOR_FINISHED;
}
void ED_OT_lib_id_load_custom_preview(wmOperatorType *ot)
{
ot->name = "Load Custom Preview";
ot->description = "Choose an image to help identify the data-block visually";
ot->idname = "ED_OT_lib_id_load_custom_preview";
/* api callbacks */
ot->poll = lib_id_preview_editing_poll;
ot->exec = lib_id_load_custom_preview_exec;
ot->invoke = WM_operator_filesel;
/* flags */
ot->flag = OPTYPE_INTERNAL;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE,
FILE_SPECIAL,
FILE_OPENFILE,
WM_FILESEL_FILEPATH,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
}
static int lib_id_generate_preview_exec(bContext *C, wmOperator *UNUSED(op))
{
PointerRNA idptr = CTX_data_pointer_get(C, "id");
ID *id = idptr.data;
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
PreviewImage *preview = BKE_previewimg_id_get(id);
if (preview) {
BKE_previewimg_clear(preview);
}
UI_icon_render_id(C, NULL, id, true, true);
WM_event_add_notifier(C, NC_ASSET, NULL);
return OPERATOR_FINISHED;
}
void ED_OT_lib_id_generate_preview(wmOperatorType *ot)
{
ot->name = "Generate Preview";
ot->description = "Create an automatic preview for the selected data-block";
ot->idname = "ED_OT_lib_id_generate_preview";
/* api callbacks */
ot->poll = lib_id_preview_editing_poll;
ot->exec = lib_id_generate_preview_exec;
/* flags */
ot->flag = OPTYPE_INTERNAL;
}

View File

@ -22,15 +22,22 @@
#include <string.h>
#include "BLI_fileops.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
#include "BKE_icons.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BLT_translation.h"
#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"
#include "ED_render.h"
#include "ED_undo.h"
#include "ED_util.h"
#include "RNA_access.h"
@ -40,7 +47,118 @@
#include "WM_api.h"
#include "WM_types.h"
static int lib_fake_user_toggle_exec(bContext *C, wmOperator *op)
/* -------------------------------------------------------------------- */
/** \name ID Previews
* \{ */
static bool lib_id_preview_editing_poll(bContext *C)
{
const PointerRNA idptr = CTX_data_pointer_get(C, "id");
BLI_assert(!idptr.data || RNA_struct_is_ID(idptr.type));
const ID *id = idptr.data;
if (!id) {
return false;
}
if (ID_IS_LINKED(id)) {
CTX_wm_operator_poll_msg_set(C, TIP_("Can't edit external library data"));
return false;
}
if (ID_IS_OVERRIDE_LIBRARY(id)) {
CTX_wm_operator_poll_msg_set(C, TIP_("Can't edit previews of overridden library data"));
return false;
}
if (!BKE_previewimg_id_get_p(id)) {
CTX_wm_operator_poll_msg_set(C, TIP_("Data-block does not support previews"));
return false;
}
return true;
}
static int lib_id_load_custom_preview_exec(bContext *C, wmOperator *op)
{
char path[FILE_MAX];
RNA_string_get(op->ptr, "filepath", path);
if (!BLI_is_file(path)) {
BKE_reportf(op->reports, RPT_ERROR, "File not found '%s'", path);
return OPERATOR_CANCELLED;
}
PointerRNA idptr = CTX_data_pointer_get(C, "id");
ID *id = idptr.data;
BKE_previewimg_id_custom_set(id, path);
WM_event_add_notifier(C, NC_ASSET, NULL);
return OPERATOR_FINISHED;
}
static void ED_OT_lib_id_load_custom_preview(wmOperatorType *ot)
{
ot->name = "Load Custom Preview";
ot->description = "Choose an image to help identify the data-block visually";
ot->idname = "ED_OT_lib_id_load_custom_preview";
/* api callbacks */
ot->poll = lib_id_preview_editing_poll;
ot->exec = lib_id_load_custom_preview_exec;
ot->invoke = WM_operator_filesel;
/* flags */
ot->flag = OPTYPE_INTERNAL;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE,
FILE_SPECIAL,
FILE_OPENFILE,
WM_FILESEL_FILEPATH,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
}
static int lib_id_generate_preview_exec(bContext *C, wmOperator *UNUSED(op))
{
PointerRNA idptr = CTX_data_pointer_get(C, "id");
ID *id = idptr.data;
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
PreviewImage *preview = BKE_previewimg_id_get(id);
if (preview) {
BKE_previewimg_clear(preview);
}
UI_icon_render_id(C, NULL, id, true, true);
WM_event_add_notifier(C, NC_ASSET, NULL);
return OPERATOR_FINISHED;
}
static void ED_OT_lib_id_generate_preview(wmOperatorType *ot)
{
ot->name = "Generate Preview";
ot->description = "Create an automatic preview for the selected data-block";
ot->idname = "ED_OT_lib_id_generate_preview";
/* api callbacks */
ot->poll = lib_id_preview_editing_poll;
ot->exec = lib_id_generate_preview_exec;
/* flags */
ot->flag = OPTYPE_INTERNAL;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Generic ID Operators
* \{ */
static int lib_id_fake_user_toggle_exec(bContext *C, wmOperator *op)
{
PropertyPointerRNA pprop;
PointerRNA idptr = PointerRNA_NULL;
@ -74,21 +192,21 @@ static int lib_fake_user_toggle_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static void ED_OT_lib_fake_user_toggle(wmOperatorType *ot)
static void ED_OT_lib_id_fake_user_toggle(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Toggle Fake User";
ot->description = "Save this data-block even if it has no users";
ot->idname = "ED_OT_lib_fake_user_toggle";
ot->idname = "ED_OT_lib_id_fake_user_toggle";
/* api callbacks */
ot->exec = lib_fake_user_toggle_exec;
ot->exec = lib_id_fake_user_toggle_exec;
/* flags */
ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
}
static int lib_unlink_exec(bContext *C, wmOperator *op)
static int lib_id_unlink_exec(bContext *C, wmOperator *op)
{
PropertyPointerRNA pprop;
PointerRNA idptr;
@ -112,20 +230,26 @@ static int lib_unlink_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static void ED_OT_lib_unlink(wmOperatorType *ot)
static void ED_OT_lib_id_unlink(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Unlink Data-Block";
ot->description = "Remove a usage of a data-block, clearing the assignment";
ot->idname = "ED_OT_lib_unlink";
ot->idname = "ED_OT_lib_id_unlink";
/* api callbacks */
ot->exec = lib_unlink_exec;
ot->exec = lib_id_unlink_exec;
/* flags */
ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name General editor utils.
* \{ */
static int ed_flush_edits_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
@ -147,9 +271,21 @@ static void ED_OT_flush_edits(wmOperatorType *ot)
ot->flag = OPTYPE_INTERNAL;
}
/** \} */
void ED_operatortypes_edutils(void)
{
WM_operatortype_append(ED_OT_lib_fake_user_toggle);
WM_operatortype_append(ED_OT_lib_unlink);
WM_operatortype_append(ED_OT_lib_id_load_custom_preview);
WM_operatortype_append(ED_OT_lib_id_generate_preview);
WM_operatortype_append(ED_OT_lib_id_fake_user_toggle);
WM_operatortype_append(ED_OT_lib_id_unlink);
WM_operatortype_append(ED_OT_flush_edits);
WM_operatortype_append(ED_OT_undo);
WM_operatortype_append(ED_OT_undo_push);
WM_operatortype_append(ED_OT_redo);
WM_operatortype_append(ED_OT_undo_redo);
WM_operatortype_append(ED_OT_undo_history);
}

View File

@ -113,6 +113,7 @@
.flip_ratio = 0.97f, \
.sys_particle_maximum = 0, \
.simulation_method = FLUID_DOMAIN_METHOD_FLIP, \
.viscosity_value = 0.05f, \
.surface_tension = 0.0f, \
.viscosity_base = 1.0f, \
.viscosity_exponent = 6.0f, \

View File

@ -52,6 +52,7 @@ enum {
FLUID_DOMAIN_DELETE_IN_OBSTACLE = (1 << 14), /* Delete fluid inside obstacles. */
FLUID_DOMAIN_USE_DIFFUSION = (1 << 15), /* Use diffusion (e.g. viscosity, surface tension). */
FLUID_DOMAIN_USE_RESUMABLE_CACHE = (1 << 16), /* Determine if cache should be resumable. */
FLUID_DOMAIN_USE_VISCOSITY = (1 << 17), /* Use viscosity. */
};
/**
@ -596,6 +597,10 @@ typedef struct FluidDomainSettings {
short simulation_method;
char _pad4[6];
/* Viscosity options. */
float viscosity_value;
char _pad5[4];
/* Diffusion options. */
float surface_tension;
float viscosity_base;
@ -610,7 +615,7 @@ typedef struct FluidDomainSettings {
int mesh_scale;
int totvert;
short mesh_generator;
char _pad5[6]; /* Unused. */
char _pad6[6]; /* Unused. */
/* Secondary particle options. */
int particle_type;
@ -631,7 +636,7 @@ typedef struct FluidDomainSettings {
int sndparticle_update_radius;
char sndparticle_boundary;
char sndparticle_combined_export;
char _pad6[6]; /* Unused. */
char _pad7[6]; /* Unused. */
/* Fluid guiding options. */
float guide_alpha; /* Guiding weight scalar (determines strength). */
@ -639,7 +644,7 @@ typedef struct FluidDomainSettings {
float guide_vel_factor; /* Multiply guiding velocity by this factor. */
int guide_res[3]; /* Res for velocity guide grids - independent from base res. */
short guide_source;
char _pad7[2]; /* Unused. */
char _pad8[2]; /* Unused. */
/* Cache options. */
int cache_frame_start;
@ -659,7 +664,7 @@ typedef struct FluidDomainSettings {
char error[64]; /* Bake error description. */
short cache_type;
char cache_id[4]; /* Run-time only */
char _pad8[2];
char _pad9[2]; /* Unused. */
/* Time options. */
float dt;
@ -694,19 +699,19 @@ typedef struct FluidDomainSettings {
char interp_method;
char gridlines_color_field; /* Simulation field used to color map onto gridlines. */
char gridlines_cell_filter;
char _pad9[7];
char _pad10[7]; /* Unused. */
/* OpenVDB cache options. */
int openvdb_compression;
float clipping;
char openvdb_data_depth;
char _pad10[7]; /* Unused. */
char _pad11[7]; /* Unused. */
/* -- Deprecated / unsed options (below). -- */
/* View options. */
int viewsettings;
char _pad11[4]; /* Unused. */
char _pad12[4]; /* Unused. */
/* Pointcache options. */
/* Smoke uses only one cache from now on (index [0]), but keeping the array for now for reading
@ -716,7 +721,7 @@ typedef struct FluidDomainSettings {
int cache_comp;
int cache_high_comp;
char cache_file_format;
char _pad12[7]; /* Unused. */
char _pad13[7]; /* Unused. */
} FluidDomainSettings;

View File

@ -1111,6 +1111,19 @@ typedef struct NodeInputVector {
float vector[3];
} NodeInputVector;
typedef struct NodeGeometryRotatePoints {
/* GeometryNodeRotatePointsType */
uint8_t type;
/* GeometryNodeRotatePointsSpace */
uint8_t space;
/* GeometryNodeAttributeInputMode */
uint8_t input_type_axis;
uint8_t input_type_angle;
uint8_t input_type_rotation;
char _pad[3];
} NodeGeometryRotatePoints;
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1
@ -1529,6 +1542,16 @@ typedef enum GeometryNodePointDistributeMethod {
GEO_NODE_POINT_DISTRIBUTE_POISSON = 1,
} GeometryNodePointDistributeMethod;
typedef enum GeometryNodeRotatePointsType {
GEO_NODE_ROTATE_POINTS_TYPE_EULER = 0,
GEO_NODE_ROTATE_POINTS_TYPE_AXIS_ANGLE = 1,
} GeometryNodeRotatePointsType;
typedef enum GeometryNodeRotatePointsSpace {
GEO_NODE_ROTATE_POINTS_SPACE_OBJECT = 0,
GEO_NODE_ROTATE_POINTS_SPACE_POINT = 1,
} GeometryNodeRotatePointsSpace;
#ifdef __cplusplus
}
#endif

View File

@ -1929,6 +1929,22 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"Maximum number of fluid particles that are allowed in this simulation");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
/* viscosity options */
prop = RNA_def_property(srna, "use_viscosity", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_VISCOSITY);
RNA_def_property_ui_text(prop, "Use Viscosity", "Enable fluid viscosity settings");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "viscosity_value", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 10.0);
RNA_def_property_ui_range(prop, 0.0, 5.0, 0.01, 3);
RNA_def_property_ui_text(prop,
"Strength",
"Viscosity of liquid (higher values result in more viscous fluids, a "
"value of 0 will still apply some viscosity)");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
/* diffusion options */
prop = RNA_def_property(srna, "use_diffusion", PROP_BOOLEAN, PROP_NONE);

View File

@ -452,6 +452,11 @@ static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_float
ITEM_FLOAT,
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_vector[] = {
ITEM_ATTRIBUTE,
ITEM_VECTOR,
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_no_boolean[] = {
ITEM_ATTRIBUTE,
ITEM_FLOAT,
@ -8584,6 +8589,66 @@ static void def_geo_attribute_color_ramp(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_geo_rotate_points(StructRNA *srna)
{
static const EnumPropertyItem type_items[] = {
{GEO_NODE_ROTATE_POINTS_TYPE_AXIS_ANGLE,
"AXIS_ANGLE",
ICON_NONE,
"Axis Angle",
"Rotate around an axis by an angle"},
{GEO_NODE_ROTATE_POINTS_TYPE_EULER,
"EULER",
ICON_NONE,
"Euler",
"Rotate around the x, y and z axis"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem space_items[] = {
{GEO_NODE_ROTATE_POINTS_SPACE_OBJECT,
"OBJECT",
ICON_NONE,
"Object",
"Rotate points in the local space of the object"},
{GEO_NODE_ROTATE_POINTS_SPACE_POINT,
"POINT",
ICON_NONE,
"Point",
"Rotate every point in its local space (as defined by the 'rotation' attribute)"},
{0, NULL, 0, NULL, NULL},
};
PropertyRNA *prop;
RNA_def_struct_sdna_from(srna, "NodeGeometryRotatePoints", "storage");
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, type_items);
RNA_def_property_ui_text(prop, "Type", "Method used to describe the rotation");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
prop = RNA_def_property(srna, "space", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, space_items);
RNA_def_property_ui_text(prop, "Space", "Base orientation of the points");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "input_type_axis", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_vector);
RNA_def_property_ui_text(prop, "Input Type Axis", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
prop = RNA_def_property(srna, "input_type_angle", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
RNA_def_property_ui_text(prop, "Input Type Angle", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
prop = RNA_def_property(srna, "input_type_rotation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_vector);
RNA_def_property_ui_text(prop, "Input Type Rotation", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
/* -------------------------------------------------------------------------- */
static void rna_def_shader_node(BlenderRNA *brna)

View File

@ -4241,8 +4241,9 @@ void rna_def_view_layer_common(StructRNA *srna, const bool scene)
prop = RNA_def_property(srna, "use_ztransp", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "layflag", SCE_LAY_ZTRA);
RNA_def_property_ui_text(
prop, "Z-Transparent", "Render Z-transparent faces in this layer (on top of Solid and Halos)");
RNA_def_property_ui_text(prop,
"Z-Transparent",
"Render Z-transparent faces in this layer (on top of Solid and Halos)");
if (scene) {
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
}

View File

@ -155,6 +155,7 @@ set(SRC
geometry/nodes/node_geo_point_distribute_poisson_disk.cc
geometry/nodes/node_geo_point_instance.cc
geometry/nodes/node_geo_point_separate.cc
geometry/nodes/node_geo_rotate_points.cc
geometry/nodes/node_geo_subdivision_surface.cc
geometry/nodes/node_geo_transform.cc
geometry/nodes/node_geo_triangulate.cc

View File

@ -42,6 +42,7 @@ void register_node_type_geo_point_separate(void);
void register_node_type_geo_attribute_compare(void);
void register_node_type_geo_attribute_mix(void);
void register_node_type_geo_attribute_color_ramp(void);
void register_node_type_geo_rotate_points(void);
#ifdef __cplusplus
}

View File

@ -284,6 +284,7 @@ DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MIX, def_geo_attribute_mix, "ATTRIBUTE_
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COLOR_RAMP, def_geo_attribute_color_ramp, "ATTRIBUTE_COLOR_RAMP", AttributeColorRamp, "Attribute Color Ramp", "")
DefNode(GeometryNode, GEO_NODE_POINT_SEPARATE, 0, "POINT_SEPARATE", PointSeparate, "Point Separate", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COMPARE, def_geo_attribute_attribute_compare, "ATTRIBUTE_COMPARE", AttributeCompare, "Attribute Compare", "")
DefNode(GeometryNode, GEO_NODE_ROTATE_POINTS, def_geo_rotate_points, "ROTATE_POINTS", RotatePoints, "Rotate Points", "")
/* undefine macros */
#undef DefNode

View File

@ -19,19 +19,28 @@
namespace blender::nodes {
/**
* Update the availability of a group of input sockets with the same name,
* used for switching between attribute inputs or single values.
*
* \param mode: Controls which socket of the group to make available.
* \param name_is_available: If false, make all sockets with this name unavailable.
*/
void update_attribute_input_socket_availabilities(bNode &node,
const StringRef name,
const GeometryNodeAttributeInputMode mode)
const GeometryNodeAttributeInputMode mode,
const bool name_is_available)
{
const GeometryNodeAttributeInputMode mode_ = (GeometryNodeAttributeInputMode)mode;
LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
if (name == socket->name) {
const bool is_available =
const bool socket_is_available =
name_is_available &&
((socket->type == SOCK_STRING && mode_ == GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE) ||
(socket->type == SOCK_FLOAT && mode_ == GEO_NODE_ATTRIBUTE_INPUT_FLOAT) ||
(socket->type == SOCK_VECTOR && mode_ == GEO_NODE_ATTRIBUTE_INPUT_VECTOR) ||
(socket->type == SOCK_RGBA && mode_ == GEO_NODE_ATTRIBUTE_INPUT_COLOR));
nodeSetSocketAvailability(socket, is_available);
nodeSetSocketAvailability(socket, socket_is_available);
}
}
}

View File

@ -41,7 +41,8 @@ bool geo_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree);
namespace blender::nodes {
void update_attribute_input_socket_availabilities(bNode &node,
const StringRef name,
const GeometryNodeAttributeInputMode mode);
const GeometryNodeAttributeInputMode mode,
const bool can_be_available = true);
CustomDataType attribute_domain_highest_complexity(Span<CustomDataType>);

View File

@ -0,0 +1,207 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "node_geometry_util.hh"
#include "BLI_math_rotation.h"
static bNodeSocketTemplate geo_node_rotate_points_in[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{SOCK_STRING, N_("Axis")},
{SOCK_VECTOR, N_("Axis"), 0.0, 0.0, 1.0, 0.0, -FLT_MAX, FLT_MAX, PROP_XYZ},
{SOCK_STRING, N_("Angle")},
{SOCK_FLOAT, N_("Angle"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX, PROP_ANGLE},
{SOCK_STRING, N_("Rotation")},
{SOCK_VECTOR, N_("Rotation"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX, PROP_EULER},
{-1, ""},
};
static bNodeSocketTemplate geo_node_rotate_points_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
namespace blender::nodes {
static void rotate_points__axis_angle__object_space(const int domain_size,
const Float3ReadAttribute &axis,
const FloatReadAttribute &angles,
MutableSpan<float3> rotations)
{
for (const int i : IndexRange(domain_size)) {
float old_rotation[3][3];
eul_to_mat3(old_rotation, rotations[i]);
float rotation[3][3];
axis_angle_to_mat3(rotation, axis[i], angles[i]);
float new_rotation[3][3];
mul_m3_m3m3(new_rotation, rotation, old_rotation);
mat3_to_eul(rotations[i], new_rotation);
}
}
static void rotate_points__axis_angle__point_space(const int domain_size,
const Float3ReadAttribute &axis,
const FloatReadAttribute &angles,
MutableSpan<float3> rotations)
{
for (const int i : IndexRange(domain_size)) {
float old_rotation[3][3];
eul_to_mat3(old_rotation, rotations[i]);
float rotation[3][3];
axis_angle_to_mat3(rotation, axis[i], angles[i]);
float new_rotation[3][3];
mul_m3_m3m3(new_rotation, old_rotation, rotation);
mat3_to_eul(rotations[i], new_rotation);
}
}
static void rotate_points__euler__object_space(const int domain_size,
const Float3ReadAttribute &eulers,
MutableSpan<float3> rotations)
{
for (const int i : IndexRange(domain_size)) {
float old_rotation[3][3];
eul_to_mat3(old_rotation, rotations[i]);
float rotation[3][3];
eul_to_mat3(rotation, eulers[i]);
float new_rotation[3][3];
mul_m3_m3m3(new_rotation, rotation, old_rotation);
mat3_to_eul(rotations[i], new_rotation);
}
}
static void rotate_points__euler__point_space(const int domain_size,
const Float3ReadAttribute &eulers,
MutableSpan<float3> rotations)
{
for (const int i : IndexRange(domain_size)) {
float old_rotation[3][3];
eul_to_mat3(old_rotation, rotations[i]);
float rotation[3][3];
eul_to_mat3(rotation, eulers[i]);
float new_rotation[3][3];
mul_m3_m3m3(new_rotation, old_rotation, rotation);
mat3_to_eul(rotations[i], new_rotation);
}
}
static void rotate_points_on_component(GeometryComponent &component,
const GeoNodeExecParams &params)
{
const bNode &node = params.node();
const NodeGeometryRotatePoints &storage = *(const NodeGeometryRotatePoints *)node.storage;
WriteAttributePtr rotation_attribute = component.attribute_try_ensure_for_write(
"rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
if (!rotation_attribute) {
return;
}
MutableSpan<float3> rotations = rotation_attribute->get_span().typed<float3>();
const int domain_size = rotations.size();
if (storage.type == GEO_NODE_ROTATE_POINTS_TYPE_AXIS_ANGLE) {
Float3ReadAttribute axis = params.get_input_attribute<float3>(
"Axis", component, ATTR_DOMAIN_POINT, {0, 0, 1});
FloatReadAttribute angles = params.get_input_attribute<float>(
"Angle", component, ATTR_DOMAIN_POINT, 0);
if (storage.space == GEO_NODE_ROTATE_POINTS_SPACE_OBJECT) {
rotate_points__axis_angle__object_space(domain_size, axis, angles, rotations);
}
else {
rotate_points__axis_angle__point_space(domain_size, axis, angles, rotations);
}
}
else {
Float3ReadAttribute eulers = params.get_input_attribute<float3>(
"Rotation", component, ATTR_DOMAIN_POINT, {0, 0, 0});
if (storage.space == GEO_NODE_ROTATE_POINTS_SPACE_OBJECT) {
rotate_points__euler__object_space(domain_size, eulers, rotations);
}
else {
rotate_points__euler__point_space(domain_size, eulers, rotations);
}
}
rotation_attribute->apply_span();
}
static void geo_node_rotate_points_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
if (geometry_set.has<MeshComponent>()) {
rotate_points_on_component(geometry_set.get_component_for_write<MeshComponent>(), params);
}
if (geometry_set.has<PointCloudComponent>()) {
rotate_points_on_component(geometry_set.get_component_for_write<PointCloudComponent>(),
params);
}
params.set_output("Geometry", geometry_set);
}
static void geo_node_rotate_points_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryRotatePoints *node_storage = (NodeGeometryRotatePoints *)MEM_callocN(
sizeof(NodeGeometryRotatePoints), __func__);
node_storage->type = GEO_NODE_ROTATE_POINTS_TYPE_EULER;
node_storage->space = GEO_NODE_ROTATE_POINTS_SPACE_OBJECT;
node_storage->input_type_axis = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
node_storage->input_type_angle = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
node_storage->input_type_rotation = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
node->storage = node_storage;
}
static void geo_node_rotate_points_update(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryRotatePoints *node_storage = (NodeGeometryRotatePoints *)node->storage;
update_attribute_input_socket_availabilities(
*node,
"Axis",
(GeometryNodeAttributeInputMode)node_storage->input_type_axis,
node_storage->type == GEO_NODE_ROTATE_POINTS_TYPE_AXIS_ANGLE);
update_attribute_input_socket_availabilities(
*node,
"Angle",
(GeometryNodeAttributeInputMode)node_storage->input_type_angle,
node_storage->type == GEO_NODE_ROTATE_POINTS_TYPE_AXIS_ANGLE);
update_attribute_input_socket_availabilities(
*node,
"Rotation",
(GeometryNodeAttributeInputMode)node_storage->input_type_rotation,
node_storage->type == GEO_NODE_ROTATE_POINTS_TYPE_EULER);
}
} // namespace blender::nodes
void register_node_type_geo_rotate_points()
{
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_ROTATE_POINTS, "Rotate Points", NODE_CLASS_GEOMETRY, 0);
node_type_socket_templates(&ntype, geo_node_rotate_points_in, geo_node_rotate_points_out);
node_type_init(&ntype, blender::nodes::geo_node_rotate_points_init);
node_type_update(&ntype, blender::nodes::geo_node_rotate_points_update);
node_type_storage(
&ntype, "NodeGeometryRotatePoints", node_free_standard_storage, node_copy_standard_storage);
ntype.geometry_node_execute = blender::nodes::geo_node_rotate_points_exec;
nodeRegisterType(&ntype);
}

View File

@ -2259,38 +2259,47 @@ static int wm_handler_fileselect_do(bContext *C,
bScreen *screen = WM_window_get_active_screen(win);
ScrArea *file_area = screen->areabase.first;
if (screen->temp && (file_area->spacetype == SPACE_FILE)) {
int win_size[2];
bool is_maximized;
ED_fileselect_window_params_get(win, win_size, &is_maximized);
ED_fileselect_params_to_userdef(file_area->spacedata.first, win_size, is_maximized);
if (BLI_listbase_is_single(&file_area->spacedata)) {
BLI_assert(ctx_win != win);
wm_window_close(C, wm, win);
CTX_wm_window_set(C, ctx_win); /* #wm_window_close() NULLs. */
/* Some operators expect a drawable context (for EVT_FILESELECT_EXEC). */
wm_window_make_drawable(wm, ctx_win);
/* Ensure correct cursor position, otherwise, popups may close immediately after
* opening (UI_BLOCK_MOVEMOUSE_QUIT). */
wm_get_cursor_position(ctx_win, &ctx_win->eventstate->x, &ctx_win->eventstate->y);
wm->winactive = ctx_win; /* Reports use this... */
if (handler->context.win == win) {
handler->context.win = NULL;
}
}
else if (file_area->full) {
ED_screen_full_prevspace(C, file_area);
}
else {
ED_area_prevspace(C, file_area);
}
temp_win = win;
break;
if ((file_area->spacetype != SPACE_FILE) || !WM_window_is_temp_screen(win)) {
continue;
}
if (ctx_area->full) {
/* Users should not be able to maximize/fullscreen an area in a temporary screen. So if
* there's a maximized file browser in a temporary screen, it was likely opened by
* #EVT_FILESELECT_FULL_OPEN. */
continue;
}
int win_size[2];
bool is_maximized;
ED_fileselect_window_params_get(win, win_size, &is_maximized);
ED_fileselect_params_to_userdef(file_area->spacedata.first, win_size, is_maximized);
if (BLI_listbase_is_single(&file_area->spacedata)) {
BLI_assert(ctx_win != win);
wm_window_close(C, wm, win);
CTX_wm_window_set(C, ctx_win); /* #wm_window_close() NULLs. */
/* Some operators expect a drawable context (for EVT_FILESELECT_EXEC). */
wm_window_make_drawable(wm, ctx_win);
/* Ensure correct cursor position, otherwise, popups may close immediately after
* opening (UI_BLOCK_MOVEMOUSE_QUIT). */
wm_get_cursor_position(ctx_win, &ctx_win->eventstate->x, &ctx_win->eventstate->y);
wm->winactive = ctx_win; /* Reports use this... */
if (handler->context.win == win) {
handler->context.win = NULL;
}
}
else if (file_area->full) {
ED_screen_full_prevspace(C, file_area);
}
else {
ED_area_prevspace(C, file_area);
}
temp_win = win;
break;
}
if (!temp_win && ctx_area->full) {