Merge branch 'master' into temp_bmesh_multires

This commit is contained in:
Joseph Eagar 2020-12-26 04:24:54 -08:00
commit 35092510ba
202 changed files with 4867 additions and 2342 deletions

View File

@ -610,6 +610,11 @@ if(WIN32)
endif()
if(UNIX)
# See WITH_WINDOWS_SCCACHE for Windows.
option(WITH_COMPILER_CCACHE "Use ccache to improve rebuild times (Works with Ninja, Makefiles and Xcode)" OFF)
endif()
# The following only works with the Ninja generator in CMake >= 3.0.
if("${CMAKE_GENERATOR}" MATCHES "Ninja")
option(WITH_NINJA_POOL_JOBS

View File

@ -41,6 +41,7 @@ Convenience Targets
* developer: Enable faster builds, error checking and tests, recommended for developers.
* config: Run cmake configuration tool to set build options.
* ninja: Use ninja build tool for faster builds.
* ccache: Use ccache for faster rebuilds.
Note: passing the argument 'BUILD_DIR=path' when calling make will override the default build dir.
Note: passing the argument 'BUILD_CMAKE_ARGS=args' lets you add cmake arguments.
@ -241,6 +242,10 @@ ifneq "$(findstring developer, $(MAKECMDGOALS))" ""
CMAKE_CONFIG_ARGS:=-C"$(BLENDER_DIR)/build_files/cmake/config/blender_developer.cmake" $(CMAKE_CONFIG_ARGS)
endif
ifneq "$(findstring ccache, $(MAKECMDGOALS))" ""
CMAKE_CONFIG_ARGS:=-DWITH_COMPILER_CCACHE=YES $(CMAKE_CONFIG_ARGS)
endif
# -----------------------------------------------------------------------------
# build tool
@ -340,6 +345,7 @@ headless: all
bpy: all
developer: all
ninja: all
ccache: all
# -----------------------------------------------------------------------------
# Build dependencies

View File

@ -2086,7 +2086,7 @@ compile_OIIO() {
cmake_d="$cmake_d -D USE_OPENCV=OFF"
cmake_d="$cmake_d -D BUILD_TESTING=OFF"
cmake_d="$cmake_d -D OIIO_BUILD_TESTS=OFF"
cmake_d="$cmake_d -D OIIO_BUILD_TOOLS=OFF"
cmake_d="$cmake_d -D OIIO_BUILD_TOOLS=ON"
cmake_d="$cmake_d -D TXT2MAN="
#cmake_d="$cmake_d -D CMAKE_EXPORT_COMPILE_COMMANDS=ON"
#cmake_d="$cmake_d -D CMAKE_VERBOSE_MAKEFILE=ON"
@ -4072,7 +4072,7 @@ install_DEB() {
else
check_package_version_ge_lt_DEB libopenimageio-dev $OIIO_VERSION_MIN $OIIO_VERSION_MAX
if [ $? -eq 0 -a "$_with_built_openexr" = false ]; then
install_packages_DEB libopenimageio-dev
install_packages_DEB libopenimageio-dev openimageio-tools
clean_OIIO
else
compile_OIIO
@ -4714,13 +4714,13 @@ install_RPM() {
INFO "Forced OpenImageIO building, as requested..."
compile_OIIO
else
#check_package_version_ge_lt_RPM OpenImageIO-devel $OIIO_VERSION_MIN $OIIO_VERSION_MAX
#if [ $? -eq 0 -a $_with_built_openexr == false ]; then
# install_packages_RPM OpenImageIO-devel
# clean_OIIO
#else
check_package_version_ge_lt_RPM OpenImageIO-devel $OIIO_VERSION_MIN $OIIO_VERSION_MAX
if [ $? -eq 0 -a $_with_built_openexr == false ]; then
install_packages_RPM OpenImageIO-devel OpenImageIO-utils
clean_OIIO
else
compile_OIIO
#fi
fi
fi

View File

@ -470,3 +470,17 @@ set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_C_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
set(CMAKE_CXX_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
if(WITH_COMPILER_CCACHE)
if(NOT CMAKE_GENERATOR STREQUAL "Xcode")
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
# Makefiles and ninja
set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}" CACHE STRING "" FORCE)
set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}" CACHE STRING "" FORCE)
else()
message(WARNING "Ccache NOT found, disabling WITH_COMPILER_CCACHE")
set(WITH_COMPILER_CCACHE OFF)
endif()
endif()
endif()

View File

@ -154,3 +154,32 @@ if(NOT ${CMAKE_GENERATOR} MATCHES "Xcode")
string(APPEND CMAKE_CXX_FLAGS " -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}")
add_definitions("-DMACOSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}")
endif()
if(WITH_COMPILER_CCACHE)
if(CMAKE_GENERATOR STREQUAL "Xcode")
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
get_filename_component(ccompiler "${CMAKE_C_COMPILER}" NAME)
get_filename_component(cxxcompiler "${CMAKE_CXX_COMPILER}" NAME)
# Ccache can figure out which compiler to use if it's invoked from
# a symlink with the name of the compiler.
# https://ccache.dev/manual/4.1.html#_run_modes
set(_fake_compiler_dir "${CMAKE_BINARY_DIR}/ccache")
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${_fake_compiler_dir})
set(_fake_C_COMPILER "${_fake_compiler_dir}/${ccompiler}")
set(_fake_CXX_COMPILER "${_fake_compiler_dir}/${cxxcompiler}")
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${CCACHE_PROGRAM}" ${_fake_C_COMPILER})
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${CCACHE_PROGRAM}" ${_fake_CXX_COMPILER})
set(CMAKE_XCODE_ATTRIBUTE_CC ${_fake_C_COMPILER} CACHE STRING "" FORCE)
set(CMAKE_XCODE_ATTRIBUTE_CXX ${_fake_CXX_COMPILER} CACHE STRING "" FORCE)
set(CMAKE_XCODE_ATTRIBUTE_LD ${_fake_C_COMPILER} CACHE STRING "" FORCE)
set(CMAKE_XCODE_ATTRIBUTE_LDPLUSPLUS ${_fake_CXX_COMPILER} CACHE STRING "" FORCE)
unset(_fake_compiler_dir)
unset(_fake_C_COMPILER)
unset(_fake_CXX_COMPILER)
else()
message(WARNING "Ccache NOT found, disabling WITH_COMPILER_CCACHE")
set(WITH_COMPILER_CCACHE OFF)
endif()
endif()
endif()

View File

@ -684,3 +684,15 @@ set(PLATFORM_LINKFLAGS
if(WITH_INSTALL_PORTABLE)
string(APPEND CMAKE_EXE_LINKER_FLAGS " -no-pie")
endif()
if(WITH_COMPILER_CCACHE)
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
# Makefiles and ninja
set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}" CACHE STRING "" FORCE)
set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}" CACHE STRING "" FORCE)
else()
message(WARNING "Ccache NOT found, disabling WITH_COMPILER_CCACHE")
set(WITH_COMPILER_CCACHE OFF)
endif()
endif()

View File

@ -72,6 +72,9 @@ protected:
/// The channel mapper reader in between.
std::shared_ptr<ChannelMapperReader> m_mapper;
/// Whether the source is being read for the first time.
bool m_first_reading;
/// Whether to keep the source if end of it is reached.
bool m_keep;

View File

@ -78,7 +78,7 @@ bool SoftwareDevice::SoftwareHandle::pause(bool keep)
}
SoftwareDevice::SoftwareHandle::SoftwareHandle(SoftwareDevice* device, std::shared_ptr<IReader> reader, std::shared_ptr<PitchReader> pitch, std::shared_ptr<ResampleReader> resampler, std::shared_ptr<ChannelMapperReader> mapper, bool keep) :
m_reader(reader), m_pitch(pitch), m_resampler(resampler), m_mapper(mapper), m_keep(keep), m_user_pitch(1.0f), m_user_volume(1.0f), m_user_pan(0.0f), m_volume(0.0f), m_old_volume(0.0f), m_loopcount(0),
m_reader(reader), m_pitch(pitch), m_resampler(resampler), m_mapper(mapper), m_first_reading(true), m_keep(keep), m_user_pitch(1.0f), m_user_volume(1.0f), m_user_pan(0.0f), m_volume(0.0f), m_old_volume(0.0f), m_loopcount(0),
m_relative(true), m_volume_max(1.0f), m_volume_min(0), m_distance_max(std::numeric_limits<float>::max()),
m_distance_reference(1.0f), m_attenuation(1.0f), m_cone_angle_outer(M_PI), m_cone_angle_inner(M_PI), m_cone_volume_outer(0),
m_flags(RENDER_CONE), m_stop(nullptr), m_stop_data(nullptr), m_status(STATUS_PLAYING), m_device(device)
@ -106,6 +106,14 @@ void SoftwareDevice::SoftwareHandle::update()
if(m_pitch->getSpecs().channels != CHANNELS_MONO)
{
m_volume = m_user_volume;
// we don't know a previous volume if this source has never been read before
if(m_first_reading)
{
m_old_volume = m_volume;
m_first_reading = false;
}
m_pitch->setPitch(m_user_pitch);
return;
}
@ -214,6 +222,13 @@ void SoftwareDevice::SoftwareHandle::update()
m_volume *= m_user_volume;
}
// we don't know a previous volume if this source has never been read before
if(m_first_reading)
{
m_old_volume = m_volume;
m_first_reading = false;
}
// 3D Cue
Quaternion orientation;
@ -754,6 +769,8 @@ void SoftwareDevice::mix(data_t* buffer, int length)
{
m_mixer->mix(buf, pos, len, sound->m_volume, sound->m_old_volume);
sound->m_old_volume = sound->m_volume;
pos += len;
if(sound->m_loopcount > 0)

View File

@ -22,6 +22,7 @@
#include <mutex>
#define KEEP_TIME 10
#define POSITION_EPSILON (1.0 / static_cast<double>(RATE_48000))
AUD_NAMESPACE_BEGIN
@ -64,7 +65,7 @@ bool SequenceHandle::updatePosition(double position)
if(m_handle.get())
{
// we currently have a handle, let's check where we are
if(position >= m_entry->m_end)
if(position - POSITION_EPSILON >= m_entry->m_end)
{
if(position >= m_entry->m_end + KEEP_TIME)
// far end, stopping
@ -76,7 +77,7 @@ bool SequenceHandle::updatePosition(double position)
return true;
}
}
else if(position >= m_entry->m_begin)
else if(position + POSITION_EPSILON >= m_entry->m_begin)
{
// inside, resuming
m_handle->resume();
@ -98,7 +99,7 @@ bool SequenceHandle::updatePosition(double position)
else
{
// we don't have a handle, let's start if we should be playing
if(position >= m_entry->m_begin && position <= m_entry->m_end)
if(position + POSITION_EPSILON >= m_entry->m_begin && position - POSITION_EPSILON <= m_entry->m_end)
{
start();
return m_valid;

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

@ -1443,6 +1443,7 @@ class CYCLES_LIGHT_PT_nodes(CyclesButtonsPanel, Panel):
class CYCLES_LIGHT_PT_spot(CyclesButtonsPanel, Panel):
bl_label = "Spot Shape"
bl_parent_id = "CYCLES_LIGHT_PT_light"
bl_context = "data"
@classmethod
@ -1454,7 +1455,6 @@ class CYCLES_LIGHT_PT_spot(CyclesButtonsPanel, Panel):
layout = self.layout
light = context.light
layout.use_property_split = True
layout.use_property_decorate = False
col = layout.column()
col.prop(light, "spot_size", text="Size")
@ -1969,9 +1969,11 @@ class CYCLES_RENDER_PT_bake_output(CyclesButtonsPanel, Panel):
if rd.bake_type == 'DISPLACEMENT':
layout.prop(rd, "use_bake_lores_mesh")
else:
layout.prop(cbk, "target")
layout.prop(cbk, "margin")
layout.prop(cbk, "use_clear", text="Clear Image")
if cbk.target == 'IMAGE_TEXTURES':
layout.prop(cbk, "margin")
layout.prop(cbk, "use_clear", text="Clear Image")
class CYCLES_RENDER_PT_debug(CyclesButtonsPanel, Panel):

View File

@ -43,42 +43,41 @@ int blender_device_threads(BL::Scene &b_scene)
DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scene, bool background)
{
if (BlenderSession::device_override != DEVICE_MASK_ALL) {
vector<DeviceInfo> devices = Device::available_devices(BlenderSession::device_override);
if (devices.empty()) {
return Device::dummy_device("Found no Cycles device of the specified type");
}
int threads = blender_device_threads(b_scene);
return Device::get_multi_device(devices, threads, background);
}
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
/* Find cycles preferences. */
PointerRNA cpreferences;
BL::Preferences::addons_iterator b_addon_iter;
for (b_preferences.addons.begin(b_addon_iter); b_addon_iter != b_preferences.addons.end();
++b_addon_iter) {
if (b_addon_iter->module() == "cycles") {
cpreferences = b_addon_iter->preferences().ptr;
break;
}
}
/* Default to CPU device. */
DeviceInfo device = Device::available_devices(DEVICE_MASK_CPU).front();
if (get_enum(cscene, "device") == 2) {
if (BlenderSession::device_override != DEVICE_MASK_ALL) {
vector<DeviceInfo> devices = Device::available_devices(BlenderSession::device_override);
if (devices.empty()) {
device = Device::dummy_device("Found no Cycles device of the specified type");
}
else {
int threads = blender_device_threads(b_scene);
device = Device::get_multi_device(devices, threads, background);
}
}
else if (get_enum(cscene, "device") == 2) {
/* Find network device. */
vector<DeviceInfo> devices = Device::available_devices(DEVICE_MASK_NETWORK);
if (!devices.empty()) {
return devices.front();
device = devices.front();
}
}
else if (get_enum(cscene, "device") == 1) {
/* Find cycles preferences. */
PointerRNA cpreferences;
BL::Preferences::addons_iterator b_addon_iter;
for (b_preferences.addons.begin(b_addon_iter); b_addon_iter != b_preferences.addons.end();
++b_addon_iter) {
if (b_addon_iter->module() == "cycles") {
cpreferences = b_addon_iter->preferences().ptr;
break;
}
}
/* Test if we are using GPU devices. */
ComputeDevice compute_device = (ComputeDevice)get_enum(
cpreferences, "compute_device_type", COMPUTE_DEVICE_NUM, COMPUTE_DEVICE_CPU);
@ -117,13 +116,13 @@ DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scen
device = Device::get_multi_device(used_devices, threads, background);
}
/* Else keep using the CPU device that was set before. */
if (!get_boolean(cpreferences, "peer_memory")) {
device.has_peer_memory = false;
}
}
}
if (!get_boolean(cpreferences, "peer_memory")) {
device.has_peer_memory = false;
}
return device;
}

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

@ -314,6 +314,14 @@ class OptiXDevice : public CUDADevice {
common_cflags += string_printf(" -I\"%s/include\"", optix_sdk_path);
}
// Specialization for shader raytracing
if (requested_features.use_shader_raytrace) {
common_cflags += " --keep-device-functions";
}
else {
common_cflags += " -D __NO_SHADER_RAYTRACE__";
}
return common_cflags;
}
@ -1240,6 +1248,12 @@ class OptiXDevice : public CUDADevice {
void build_bvh(BVH *bvh, Progress &progress, bool refit) override
{
if (bvh->params.bvh_layout == BVH_LAYOUT_BVH2) {
/* For baking CUDA is used, build appropriate BVH for that. */
Device::build_bvh(bvh, progress, refit);
return;
}
BVHOptiX *const bvh_optix = static_cast<BVHOptiX *>(bvh);
progress.set_substatus("Building OptiX acceleration structure");

View File

@ -214,13 +214,6 @@ ccl_device_inline float3 object_location(KernelGlobals *kg, const ShaderData *sd
#endif
}
/* Total surface area of object */
ccl_device_inline float object_surface_area(KernelGlobals *kg, int object)
{
return kernel_tex_fetch(__objects, object).surface_area;
}
/* Color of the object */
ccl_device_inline float3 object_color(KernelGlobals *kg, int object)
@ -328,7 +321,7 @@ ccl_device_inline float object_volume_density(KernelGlobals *kg, int object)
return 1.0f;
}
return kernel_tex_fetch(__objects, object).surface_area;
return kernel_tex_fetch(__objects, object).volume_density;
}
ccl_device_inline float object_volume_step_size(KernelGlobals *kg, int object)

View File

@ -1461,7 +1461,7 @@ typedef struct KernelObject {
Transform tfm;
Transform itfm;
float surface_area;
float volume_density;
float pass_id;
float random_number;
float color[3];

View File

@ -109,7 +109,7 @@ static void shaderdata_to_shaderglobals(
globals->dvdy = sd->dv.dy;
globals->dPdu = TO_VEC3(sd->dPdu);
globals->dPdv = TO_VEC3(sd->dPdv);
globals->surfacearea = (sd->object == OBJECT_NONE) ? 1.0f : object_surface_area(kg, sd->object);
globals->surfacearea = 1.0f;
globals->time = sd->time;
/* booleans */

View File

@ -55,12 +55,6 @@ struct UpdateObjectTransformState {
*/
map<ParticleSystem *, int> particle_offset;
/* Mesh area.
* Used to avoid calculation of mesh area multiple times. Used for both
* read and write. Acquire surface_area_lock to keep it all thread safe.
*/
map<Mesh *, float> surface_area_map;
/* Motion offsets for each object. */
array<uint> motion_offset;
@ -76,12 +70,8 @@ struct UpdateObjectTransformState {
bool have_curves;
/* ** Scheduling queue. ** */
Scene *scene;
/* Some locks to keep everything thread-safe. */
thread_spin_lock surface_area_lock;
/* First unused object index in the queue. */
int queue_start_object;
};
@ -379,80 +369,17 @@ ObjectManager::~ObjectManager()
{
}
static float object_surface_area(UpdateObjectTransformState *state,
const Transform &tfm,
Geometry *geom)
static float object_volume_density(const Transform &tfm, Geometry *geom)
{
if (geom->geometry_type != Geometry::MESH && geom->geometry_type != Geometry::VOLUME) {
return 0.0f;
}
Mesh *mesh = static_cast<Mesh *>(geom);
if (mesh->has_volume || geom->geometry_type == Geometry::VOLUME) {
if (geom->geometry_type == Geometry::VOLUME) {
/* Volume density automatically adjust to object scale. */
if (geom->geometry_type == Geometry::VOLUME &&
static_cast<Volume *>(geom)->get_object_space()) {
if (static_cast<Volume *>(geom)->get_object_space()) {
const float3 unit = normalize(make_float3(1.0f, 1.0f, 1.0f));
return 1.0f / len(transform_direction(&tfm, unit));
}
else {
return 1.0f;
}
}
/* Compute surface area. for uniform scale we can do avoid the many
* transform calls and share computation for instances.
*
* TODO(brecht): Correct for displacement, and move to a better place.
*/
float surface_area = 0.0f;
float uniform_scale;
if (transform_uniform_scale(tfm, uniform_scale)) {
map<Mesh *, float>::iterator it;
/* NOTE: This isn't fully optimal and could in theory lead to multiple
* threads calculating area of the same mesh in parallel. However, this
* also prevents suspending all the threads when some mesh's area is
* not yet known.
*/
state->surface_area_lock.lock();
it = state->surface_area_map.find(mesh);
state->surface_area_lock.unlock();
if (it == state->surface_area_map.end()) {
size_t num_triangles = mesh->num_triangles();
for (size_t j = 0; j < num_triangles; j++) {
Mesh::Triangle t = mesh->get_triangle(j);
float3 p1 = mesh->get_verts()[t.v[0]];
float3 p2 = mesh->get_verts()[t.v[1]];
float3 p3 = mesh->get_verts()[t.v[2]];
surface_area += triangle_area(p1, p2, p3);
}
state->surface_area_lock.lock();
state->surface_area_map[mesh] = surface_area;
state->surface_area_lock.unlock();
}
else {
surface_area = it->second;
}
surface_area *= uniform_scale;
}
else {
size_t num_triangles = mesh->num_triangles();
for (size_t j = 0; j < num_triangles; j++) {
Mesh::Triangle t = mesh->get_triangle(j);
float3 p1 = transform_point(&tfm, mesh->get_verts()[t.v[0]]);
float3 p2 = transform_point(&tfm, mesh->get_verts()[t.v[1]]);
float3 p3 = transform_point(&tfm, mesh->get_verts()[t.v[2]]);
surface_area += triangle_area(p1, p2, p3);
}
}
return surface_area;
return 1.0f;
}
void ObjectManager::device_update_object_transform(UpdateObjectTransformState *state, Object *ob)
@ -476,7 +403,7 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
kobject.tfm = tfm;
kobject.itfm = itfm;
kobject.surface_area = object_surface_area(state, tfm, geom);
kobject.volume_density = object_volume_density(tfm, geom);
kobject.color[0] = color.x;
kobject.color[1] = color.y;
kobject.color[2] = color.z;

View File

@ -548,22 +548,23 @@ void SVMCompiler::generated_shared_closure_nodes(ShaderNode *root_node,
}
}
void SVMCompiler::generate_aov_node(ShaderNode *node, CompilerState *state)
void SVMCompiler::find_aov_nodes_and_dependencies(ShaderNodeSet &aov_nodes,
ShaderGraph *graph,
CompilerState *state)
{
/* execute dependencies for node */
foreach (ShaderInput *in, node->inputs) {
if (in->link != NULL) {
ShaderNodeSet dependencies;
find_dependencies(dependencies, state->nodes_done, in);
generate_svm_nodes(dependencies, state);
foreach (ShaderNode *node, graph->nodes) {
if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT_AOV) {
OutputAOVNode *aov_node = static_cast<OutputAOVNode *>(node);
if (aov_node->slot >= 0) {
aov_nodes.insert(aov_node);
foreach (ShaderInput *in, node->inputs) {
if (in->link != NULL) {
find_dependencies(aov_nodes, state->nodes_done, in);
}
}
}
}
}
/* compile node itself */
generate_node(node, state->nodes_done);
state->nodes_done.insert(node);
state->nodes_done_flag[node->id] = true;
}
void SVMCompiler::generate_multi_closure(ShaderNode *root_node,
@ -631,6 +632,25 @@ void SVMCompiler::generate_multi_closure(ShaderNode *root_node,
}
}
/* For dependencies AOV nodes, prevent them from being categorized
* as exclusive deps of one or the other closure, since the need to
* execute them for AOV writing is not dependent on the closure
* weights. */
if (state->aov_nodes.size()) {
set_intersection(state->aov_nodes.begin(),
state->aov_nodes.end(),
cl1deps.begin(),
cl1deps.end(),
std::inserter(shareddeps, shareddeps.begin()),
node_id_comp);
set_intersection(state->aov_nodes.begin(),
state->aov_nodes.end(),
cl2deps.begin(),
cl2deps.end(),
std::inserter(shareddeps, shareddeps.begin()),
node_id_comp);
}
if (!shareddeps.empty()) {
if (cl1in->link) {
generated_shared_closure_nodes(root_node, cl1in->link->parent, state, shareddeps);
@ -782,6 +802,9 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
}
if (generate) {
if (type == SHADER_TYPE_SURFACE) {
find_aov_nodes_and_dependencies(state.aov_nodes, graph, &state);
}
generate_multi_closure(clin->link->parent, clin->link->parent, &state);
}
}
@ -789,28 +812,15 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
/* compile output node */
output->compile(*this);
if (type == SHADER_TYPE_SURFACE) {
vector<OutputAOVNode *> aov_outputs;
foreach (ShaderNode *node, graph->nodes) {
if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT_AOV) {
OutputAOVNode *aov_node = static_cast<OutputAOVNode *>(node);
if (aov_node->slot >= 0) {
aov_outputs.push_back(aov_node);
}
}
}
if (aov_outputs.size() > 0) {
/* AOV passes are only written if the object is directly visible, so
* there is no point in evaluating all the nodes generated only for the
* AOV outputs if that's not the case. Therefore, we insert
* NODE_AOV_START into the shader before the AOV-only nodes are
* generated which tells the kernel that it can stop evaluation
* early if AOVs will not be written. */
add_node(NODE_AOV_START, 0, 0, 0);
foreach (OutputAOVNode *node, aov_outputs) {
generate_aov_node(node, &state);
}
}
if (!state.aov_nodes.empty()) {
/* AOV passes are only written if the object is directly visible, so
* there is no point in evaluating all the nodes generated only for the
* AOV outputs if that's not the case. Therefore, we insert
* NODE_AOV_START into the shader before the AOV-only nodes are
* generated which tells the kernel that it can stop evaluation
* early if AOVs will not be written. */
add_node(NODE_AOV_START, 0, 0, 0);
generate_svm_nodes(state.aov_nodes, &state);
}
}

View File

@ -176,6 +176,9 @@ class SVMCompiler {
/* Set of closures which were already compiled. */
ShaderNodeSet closure_done;
/* Set of nodes used for writing AOVs. */
ShaderNodeSet aov_nodes;
/* ** SVM nodes generation state ** */
/* Flag whether the node with corresponding ID was already compiled or
@ -197,6 +200,9 @@ class SVMCompiler {
const ShaderNodeSet &done,
ShaderInput *input,
ShaderNode *skip_node = NULL);
void find_aov_nodes_and_dependencies(ShaderNodeSet &aov_nodes,
ShaderGraph *graph,
CompilerState *state);
void generate_node(ShaderNode *node, ShaderNodeSet &done);
void generate_aov_node(ShaderNode *node, CompilerState *state);
void generate_closure_node(ShaderNode *node, CompilerState *state);

View File

@ -569,13 +569,13 @@ GHOST_TSuccess GHOST_SystemWin32::getButtons(GHOST_Buttons &buttons) const
*/
bool swapped = ::GetSystemMetrics(SM_SWAPBUTTON) == TRUE;
bool down = HIBYTE(::GetKeyState(VK_LBUTTON)) != 0;
bool down = HIBYTE(::GetAsyncKeyState(VK_LBUTTON)) != 0;
buttons.set(swapped ? GHOST_kButtonMaskRight : GHOST_kButtonMaskLeft, down);
down = HIBYTE(::GetKeyState(VK_MBUTTON)) != 0;
down = HIBYTE(::GetAsyncKeyState(VK_MBUTTON)) != 0;
buttons.set(GHOST_kButtonMaskMiddle, down);
down = HIBYTE(::GetKeyState(VK_RBUTTON)) != 0;
down = HIBYTE(::GetAsyncKeyState(VK_RBUTTON)) != 0;
buttons.set(swapped ? GHOST_kButtonMaskLeft : GHOST_kButtonMaskRight, down);
return GHOST_kSuccess;
}
@ -939,148 +939,106 @@ GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type,
{
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
if (type == GHOST_kEventButtonDown) {
window->updateMouseCapture(MousePressed);
}
else if (type == GHOST_kEventButtonUp) {
window->updateMouseCapture(MouseReleased);
}
GHOST_TabletData td = window->m_tabletInRange ? window->getLastTabletData() :
GHOST_TABLET_DATA_NONE;
/* Check for active Wintab mouse emulation in addition to a tablet in range because a proximity
* leave event might have fired before the Windows mouse up event, thus there are still tablet
* events to grab. The described behavior was observed in a Wacom Bamboo CTE-450. */
if (window->useTabletAPI(GHOST_kTabletWintab) &&
(window->m_tabletInRange || window->wintabSysButPressed()) &&
processWintabEvent(type, window, mask, window->getMousePressed())) {
/* Wintab processing only handles in-contact events. */
return NULL;
}
/* Ensure button click occurs at its intended position. */
DWORD msgPos = ::GetMessagePos();
GHOST_TInt32 x_screen = GET_X_LPARAM(msgPos), y_screen = GET_Y_LPARAM(msgPos);
system->pushEvent(new GHOST_EventCursor(
system->getMilliSeconds(), GHOST_kEventCursorMove, window, x_screen, y_screen, td));
return new GHOST_EventButton(
system->getMilliSeconds(), type, window, mask, GHOST_TABLET_DATA_NONE);
window->updateMouseCapture(type == GHOST_kEventButtonDown ? MousePressed : MouseReleased);
return new GHOST_EventButton(system->getMilliSeconds(), type, window, mask, td);
}
GHOST_TSuccess GHOST_SystemWin32::processWintabEvent(GHOST_TEventType type,
GHOST_WindowWin32 *window,
GHOST_TButtonMask mask,
bool mousePressed)
void GHOST_SystemWin32::processWintabEvent(GHOST_WindowWin32 *window)
{
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
/* Only process Wintab packets if we can correlate them to a Window's mouse button event. When a
* button event associated to a mouse button by Wintab occurs outside of WM_*BUTTON events,
* there's no way to tell if other simultaneously pressed non-mouse mapped buttons are associated
* to a modifier key (shift, alt, ctrl) or a system event (scroll, etc.) and thus it is not
* possible to determine if a mouse click event should occur. */
if (!mousePressed && !window->wintabSysButPressed()) {
return GHOST_kFailure;
}
std::vector<GHOST_WintabInfoWin32> wintabInfo;
if (!window->getWintabInfo(wintabInfo)) {
return GHOST_kFailure;
return;
}
auto wtiIter = wintabInfo.begin();
/* We only process events that correlate to a mouse button events, so there may exist Wintab
* button down events that were instead mapped to e.g. scroll still in the queue. We need to
* skip those and find the last button down mapped to mouse buttons. */
if (!window->wintabSysButPressed()) {
/* Assume there may be no button down event currently in the queue. */
wtiIter = wintabInfo.end();
for (auto it = wintabInfo.begin(); it != wintabInfo.end(); it++) {
if (it->type == GHOST_kEventButtonDown) {
wtiIter = it;
}
}
}
bool unhandledButton = type != GHOST_kEventCursorMove;
for (; wtiIter != wintabInfo.end(); wtiIter++) {
auto info = *wtiIter;
for (auto info : wintabInfo) {
switch (info.type) {
case GHOST_kEventButtonDown: {
/* While changing windows with a tablet, Window's mouse button events normally occur before
* tablet proximity events, so a button up event can't be differentiated as occurring from
* a Wintab tablet or a normal mouse and a Ghost button event will always be generated.
*
* If we were called during a button down event create a ghost button down event, otherwise
* don't duplicate the prior button down as it interrupts drawing immediately after
* changing a window. */
case GHOST_kEventCursorMove: {
system->pushEvent(new GHOST_EventCursor(
info.time, GHOST_kEventCursorMove, window, info.x, info.y, info.tabletData));
if (type == GHOST_kEventButtonDown && mask == info.button) {
break;
}
case GHOST_kEventButtonDown: {
system->pushEvent(new GHOST_EventCursor(
info.time, GHOST_kEventCursorMove, window, info.x, info.y, info.tabletData));
UINT message;
switch (info.button) {
case GHOST_kButtonMaskLeft:
message = WM_LBUTTONDOWN;
break;
case GHOST_kButtonMaskRight:
message = WM_RBUTTONDOWN;
break;
case GHOST_kButtonMaskMiddle:
message = WM_MBUTTONDOWN;
break;
default:
continue;
}
MSG msg;
if (PeekMessage(&msg, window->getHWND(), message, message, PM_REMOVE | PM_NOYIELD) &&
WM_QUIT != msg.message) {
window->updateMouseCapture(MousePressed);
system->pushEvent(
new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData));
unhandledButton = false;
}
window->updateWintabSysBut(MousePressed);
break;
}
case GHOST_kEventCursorMove:
system->pushEvent(new GHOST_EventCursor(
info.time, GHOST_kEventCursorMove, window, info.x, info.y, info.tabletData));
break;
case GHOST_kEventButtonUp:
system->pushEvent(
new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData));
if (type == GHOST_kEventButtonUp && mask == info.button) {
unhandledButton = false;
case GHOST_kEventButtonUp: {
UINT message;
switch (info.button) {
case GHOST_kButtonMaskLeft:
message = WM_LBUTTONUP;
break;
case GHOST_kButtonMaskRight:
message = WM_RBUTTONUP;
break;
case GHOST_kButtonMaskMiddle:
message = WM_MBUTTONUP;
break;
default:
continue;
}
MSG msg;
if (PeekMessage(&msg, window->getHWND(), message, message, PM_REMOVE | PM_NOYIELD) &&
WM_QUIT != msg.message) {
window->updateMouseCapture(MouseReleased);
system->pushEvent(
new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData));
}
window->updateWintabSysBut(MouseReleased);
break;
}
default:
break;
}
}
/* No Wintab button found correlating to the system button event, handle it too.
*
* Wintab button up events may be handled during WM_MOUSEMOVE, before their corresponding
* WM_*BUTTONUP event has fired, which results in two GHOST Button up events for a single Wintab
* associated button event. Alternatively this Windows button up event may have been generated
* from a non-stylus device such as a button on the tablet pad and needs to be handled for some
* workflows.
*
* The ambiguity introduced by Windows and Wintab buttons being asynchronous and having no
* definitive way to associate each, and that the Wintab API does not provide enough information
* to differentiate whether the stylus down is or is not modified by another button to a
* non-mouse mapping, means that we must pessimistically generate mouse up events when we are
* unsure of an association to prevent the mouse locking into a down state. */
if (unhandledButton) {
if (!window->wintabSysButPressed()) {
GHOST_TInt32 x, y;
system->getCursorPosition(x, y);
system->pushEvent(new GHOST_EventCursor(system->getMilliSeconds(),
GHOST_kEventCursorMove,
window,
x,
y,
GHOST_TABLET_DATA_NONE));
}
system->pushEvent(new GHOST_EventButton(
system->getMilliSeconds(), type, window, mask, GHOST_TABLET_DATA_NONE));
}
return GHOST_kSuccess;
}
void GHOST_SystemWin32::processPointerEvent(
UINT type, GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam, bool &eventHandled)
{
std::vector<GHOST_PointerInfoWin32> pointerInfo;
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
/* Pointer events might fire when changing windows for a device which is set to use Wintab, even
* when when Wintab is left enabled but set to the bottom of Wintab overlap order. */
if (!window->useTabletAPI(GHOST_kTabletNative)) {
return;
}
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
std::vector<GHOST_PointerInfoWin32> pointerInfo;
if (window->getPointerInfo(pointerInfo, wParam, lParam) != GHOST_kSuccess) {
return;
}
@ -1148,36 +1106,16 @@ void GHOST_SystemWin32::processPointerEvent(
GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *window)
{
GHOST_TInt32 x_screen, y_screen;
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
GHOST_TabletData tabletData = GHOST_TABLET_DATA_NONE;
if (window->m_tabletInRange || window->wintabSysButPressed()) {
if (window->useTabletAPI(GHOST_kTabletWintab) &&
processWintabEvent(
GHOST_kEventCursorMove, window, GHOST_kButtonMaskNone, window->getMousePressed())) {
return NULL;
}
else if (window->useTabletAPI(GHOST_kTabletNative)) {
/* Tablet input handled in WM_POINTER* events. WM_MOUSEMOVE events in response to tablet
* input aren't normally generated when using WM_POINTER events, but manually moving the
* system cursor as we do in WM_POINTER handling does. */
return NULL;
}
/* If using Wintab but no button event is currently active, fall through to default handling.
*
* Populate tablet data so that cursor is recognized as an absolute position device. */
tabletData.Active = GHOST_kTabletModeStylus;
tabletData.Pressure = 0.0f;
tabletData.Xtilt = 0.0f;
tabletData.Ytilt = 0.0f;
if (window->m_tabletInRange) {
return NULL;
}
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
GHOST_TInt32 x_screen, y_screen;
system->getCursorPosition(x_screen, y_screen);
if (window->getCursorGrabModeIsWarp() && !window->m_tabletInRange) {
if (window->getCursorGrabModeIsWarp()) {
GHOST_TInt32 x_new = x_screen;
GHOST_TInt32 y_new = y_screen;
GHOST_TInt32 x_accum, y_accum;
@ -1205,12 +1143,16 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
window,
x_screen + x_accum,
y_screen + y_accum,
tabletData);
GHOST_TABLET_DATA_NONE);
}
}
else {
return new GHOST_EventCursor(
system->getMilliSeconds(), GHOST_kEventCursorMove, window, x_screen, y_screen, tabletData);
return new GHOST_EventCursor(system->getMilliSeconds(),
GHOST_kEventCursorMove,
window,
x_screen,
y_screen,
GHOST_TABLET_DATA_NONE);
}
return NULL;
}
@ -1320,6 +1262,23 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA
return event;
}
GHOST_Event *GHOST_SystemWin32::processWindowSizeEvent(GHOST_WindowWin32 *window)
{
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
GHOST_Event *sizeEvent = new GHOST_Event(
system->getMilliSeconds(), GHOST_kEventWindowSize, window);
/* We get WM_SIZE before we fully init. Do not dispatch before we are continuously resizing. */
if (window->m_inLiveResize) {
system->pushEvent(sizeEvent);
system->dispatchEvents();
return NULL;
}
else {
return sizeEvent;
}
}
GHOST_Event *GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type,
GHOST_WindowWin32 *window)
{
@ -1359,12 +1318,10 @@ void GHOST_SystemWin32::setTabletAPI(GHOST_TTabletAPI api)
GHOST_System::setTabletAPI(api);
GHOST_WindowManager *wm = getWindowManager();
GHOST_WindowWin32 *activeWindow = (GHOST_WindowWin32 *)wm->getActiveWindow();
for (GHOST_IWindow *win : wm->getWindows()) {
GHOST_WindowWin32 *windowsWindow = (GHOST_WindowWin32 *)win;
windowsWindow->updateWintab(windowsWindow == activeWindow,
!::IsIconic(windowsWindow->getHWND()));
GHOST_WindowWin32 *windowWin32 = (GHOST_WindowWin32 *)win;
windowWin32->setWintabEnabled(windowWin32->useTabletAPI(GHOST_kTabletWintab));
}
}
@ -1609,15 +1566,23 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
////////////////////////////////////////////////////////////////////////
case WT_INFOCHANGE: {
window->processWintabInfoChangeEvent(lParam);
eventHandled = true;
break;
}
case WT_CSRCHANGE:
window->updateWintabCursorInfo();
eventHandled = true;
break;
case WT_PROXIMITY: {
bool inRange = LOWORD(lParam);
window->processWintabProximityEvent(inRange);
if (window->useTabletAPI(GHOST_kTabletWintab)) {
window->m_tabletInRange = LOWORD(lParam);
}
eventHandled = true;
break;
}
case WT_PACKET:
window->updateWintabEventsSyncTime();
processWintabEvent(window);
eventHandled = true;
break;
////////////////////////////////////////////////////////////////////////
// Pointer events, processed
@ -1667,6 +1632,15 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
}
break;
case WM_MOUSEMOVE:
if (!window->m_mousePresent) {
TRACKMOUSEEVENT tme = {sizeof(tme)};
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = hwnd;
TrackMouseEvent(&tme);
window->m_mousePresent = true;
window->setWintabOverlap(true);
}
event = processCursorEvent(window);
break;
case WM_MOUSEWHEEL: {
@ -1709,7 +1683,10 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
window->loadCursor(true, GHOST_kStandardCursorDefault);
}
break;
case WM_MOUSELEAVE:
window->m_mousePresent = false;
window->setWintabOverlap(false);
break;
////////////////////////////////////////////////////////////////////////
// Mouse events, ignored
////////////////////////////////////////////////////////////////////////
@ -1725,7 +1702,6 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
* is sent to the window that has captured the mouse.
*/
break;
////////////////////////////////////////////////////////////////////////
// Window events, processed
////////////////////////////////////////////////////////////////////////
@ -1758,8 +1734,6 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
if (LOWORD(wParam) == WA_INACTIVE)
window->lostMouseCapture();
window->updateWintab(LOWORD(wParam) != WA_INACTIVE, !::IsIconic(window->getHWND()));
lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
break;
}
@ -1801,6 +1775,8 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
/* Let DefWindowProc handle it. */
break;
case WM_SIZING:
event = processWindowSizeEvent(window);
break;
case WM_SIZE:
/* The WM_SIZE message is sent to a window after its size has changed.
* The WM_SIZE and WM_MOVE messages are not sent if an application handles the
@ -1808,21 +1784,13 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
* to perform any move or size change processing during the WM_WINDOWPOSCHANGED
* message without calling DefWindowProc.
*/
/* we get first WM_SIZE before we fully init.
* So, do not dispatch before we continuously resizing. */
if (window->m_inLiveResize) {
system->pushEvent(processWindowEvent(GHOST_kEventWindowSize, window));
system->dispatchEvents();
}
else {
event = processWindowEvent(GHOST_kEventWindowSize, window);
}
event = processWindowSizeEvent(window);
/* Window might be minimized while inactive. When a window is inactive but not minimized,
* Wintab is left enabled (to catch the case where a pen is used to activate a window).
* When an inactive window is minimized, we need to disable Wintab. */
if (msg == WM_SIZE && wParam == SIZE_MINIMIZED) {
window->updateWintab(false, false);
if (wParam == SIZE_MINIMIZED) {
window->setWintabEnabled(false);
}
else if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED) {
window->setWintabEnabled(true);
}
break;

View File

@ -322,16 +322,9 @@ class GHOST_SystemWin32 : public GHOST_System {
/**
* Creates tablet events from Wintab events.
* \param type: The type of pointer event.
* \param window: The window receiving the event (the active window).
* \param mask: The button mask of the calling event.
* \param mousePressed: Whether the mouse is currently pressed.
* \return True if the method handled the event.
*/
static GHOST_TSuccess processWintabEvent(GHOST_TEventType type,
GHOST_WindowWin32 *window,
GHOST_TButtonMask mask,
bool mousePressed);
static void processWintabEvent(GHOST_WindowWin32 *window);
/**
* Creates tablet events from pointer events.
@ -376,6 +369,13 @@ class GHOST_SystemWin32 : public GHOST_System {
*/
GHOST_TKey processSpecialKey(short vKey, short scanCode) const;
/**
* Creates a window size event.
* \param window: The window receiving the event (the active window).
* \return The event created.
*/
static GHOST_Event *processWindowSizeEvent(GHOST_WindowWin32 *window);
/**
* Creates a window event.
* \param type: The type of event to create.

View File

@ -905,8 +905,8 @@ GHOST_TSuccess GHOST_WindowCocoa::setProgressBar(float progress)
static void postNotification()
{
NSUserNotification *notification = [[NSUserNotification alloc] init];
notification.title = @"Blender progress notification";
notification.informativeText = @"Calculation is finished";
notification.title = @"Blender Progress Notification";
notification.informativeText = @"Calculation is finished.";
notification.soundName = NSUserNotificationDefaultSoundName;
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
[notification release];

View File

@ -104,6 +104,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
bool is_debug,
bool dialog)
: GHOST_Window(width, height, state, wantStereoVisual, false),
m_mousePresent(false),
m_tabletInRange(false),
m_inLiveResize(false),
m_system(system),
@ -341,8 +342,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
(m_wintab.enable = (GHOST_WIN32_WTEnable)::GetProcAddress(m_wintab.handle, "WTEnable")) &&
(m_wintab.overlap = (GHOST_WIN32_WTOverlap)::GetProcAddress(m_wintab.handle, "WTOverlap"))) {
initializeWintab();
// Determine which tablet API to use and enable it.
updateWintab(m_system->m_windowFocus, m_system->m_windowFocus);
setWintabEnabled(true);
}
CoCreateInstance(
@ -358,13 +358,12 @@ GHOST_WindowWin32::~GHOST_WindowWin32()
}
if (m_wintab.handle) {
updateWintab(false, false);
setWintabEnabled(false);
if (m_wintab.close && m_wintab.context) {
m_wintab.close(m_wintab.context);
}
FreeLibrary(m_wintab.handle);
memset(&m_wintab, 0, sizeof(m_wintab));
}
if (m_user32) {
@ -803,32 +802,6 @@ void GHOST_WindowWin32::updateMouseCapture(GHOST_MouseCaptureEventWin32 event)
}
}
bool GHOST_WindowWin32::getMousePressed() const
{
return m_nPressedButtons;
}
bool GHOST_WindowWin32::wintabSysButPressed() const
{
return m_wintab.numSysButtons;
}
void GHOST_WindowWin32::updateWintabSysBut(GHOST_MouseCaptureEventWin32 event)
{
switch (event) {
case MousePressed:
m_wintab.numSysButtons++;
break;
case MouseReleased:
if (m_wintab.numSysButtons)
m_wintab.numSysButtons--;
break;
case OperatorGrab:
case OperatorUngrab:
break;
}
}
HCURSOR GHOST_WindowWin32::getStandardCursor(GHOST_TStandardCursor shape) const
{
// Convert GHOST cursor to Windows OEM cursor
@ -1032,28 +1005,6 @@ GHOST_TSuccess GHOST_WindowWin32::hasCursorShape(GHOST_TStandardCursor cursorSha
return (getStandardCursor(cursorShape)) ? GHOST_kSuccess : GHOST_kFailure;
}
void GHOST_WindowWin32::updateWintab(bool active, bool visible)
{
if (m_wintab.enable && m_wintab.overlap && m_wintab.context) {
bool enable = useTabletAPI(GHOST_kTabletWintab) && visible;
bool overlap = enable && active;
/* Disabling context while the Window is not minimized can cause issues on receiving Wintab
* input while changing a window for some drivers, so only disable if either Wintab had been
* disabled or the window is minimized. */
m_wintab.enable(m_wintab.context, enable);
m_wintab.overlap(m_wintab.context, overlap);
if (!overlap) {
/* WT_PROXIMITY event doesn't occur unless tablet's cursor leaves the proximity while the
* window is active. */
m_tabletInRange = false;
m_wintab.numSysButtons = 0;
m_wintab.sysButtonsPressed = 0;
}
}
}
void GHOST_WindowWin32::initializeWintab()
{
/* Return if wintab library handle doesn't exist or wintab is already initialized. */
@ -1066,8 +1017,6 @@ void GHOST_WindowWin32::initializeWintab()
if (m_wintab.open && m_wintab.info && m_wintab.queueSizeGet && m_wintab.queueSizeSet &&
call_wt_info(m_wintab.info, WTI_DEFSYSCTX, 0, &lc)) {
/* The pressure and orientation (tilt) */
AXIS Pressure, Orientation[3];
lc.lcPktData = PACKETDATA;
lc.lcPktMode = PACKETMODE;
lc.lcMoveMask = PACKETDATA;
@ -1078,19 +1027,7 @@ void GHOST_WindowWin32::initializeWintab()
m_wintab.info(WTI_INTERFACE, IFC_NDEVICES, &m_wintab.numDevices);
BOOL pressureSupport = m_wintab.info(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
m_wintab.maxPressure = pressureSupport ? Pressure.axMax : 0;
BOOL tiltSupport = m_wintab.info(WTI_DEVICES, DVC_ORIENTATION, &Orientation);
/* Does the tablet support azimuth ([0]) and altitude ([1])? */
if (tiltSupport && Orientation[0].axResolution && Orientation[1].axResolution) {
/* All this assumes the minimum is 0. */
m_wintab.maxAzimuth = Orientation[0].axMax;
m_wintab.maxAltitude = Orientation[1].axMax;
}
else { /* No so dont do tilt stuff. */
m_wintab.maxAzimuth = m_wintab.maxAltitude = 0;
}
updateWintabCursorInfo();
/* The Wintab spec says we must open the context disabled if we are using cursor masks. */
m_wintab.context = m_wintab.open(m_hWnd, &lc, FALSE);
@ -1203,9 +1140,63 @@ GHOST_TSuccess GHOST_WindowWin32::getPointerInfo(
}
}
if (!outPointerInfo.empty()) {
lastTabletData = outPointerInfo.back().tabletData;
}
return GHOST_kSuccess;
}
void GHOST_WindowWin32::setWintabEnabled(bool enable)
{
if (m_wintab.enable && m_wintab.get && m_wintab.context) {
LOGCONTEXT context = {0};
if (m_wintab.get(m_wintab.context, &context)) {
if (enable && context.lcStatus & CXS_DISABLED && useTabletAPI(GHOST_kTabletWintab)) {
m_wintab.enable(m_wintab.context, true);
POINT cursorPos;
::GetCursorPos(&cursorPos);
GHOST_Rect bounds;
getClientBounds(bounds);
if (bounds.isInside(cursorPos.x, cursorPos.y)) {
setWintabOverlap(true);
}
}
else if (!enable && !(context.lcStatus & CXS_DISABLED)) {
setWintabOverlap(false);
m_wintab.enable(m_wintab.context, false);
}
}
}
}
void GHOST_WindowWin32::setWintabOverlap(bool overlap)
{
if (m_wintab.overlap && m_wintab.get && m_wintab.packetsGet && m_wintab.context) {
LOGCONTEXT context = {0};
if (m_wintab.get(m_wintab.context, &context)) {
if (overlap && context.lcStatus & CXS_OBSCURED && useTabletAPI(GHOST_kTabletWintab)) {
m_wintab.overlap(m_wintab.context, true);
}
else if (!overlap && context.lcStatus & CXS_ONTOP) {
m_wintab.overlap(m_wintab.context, false);
/* If context is disabled, Windows Ink may be active and managing m_tabletInRange. Don't
* modify it. */
if (!(context.lcStatus & CXS_DISABLED)) {
/* Set tablet as not in range, proximity event may not occur. */
m_tabletInRange = false;
/* Clear the packet queue. */
m_wintab.packetsGet(m_wintab.context, m_wintab.pkts.size(), m_wintab.pkts.data());
}
}
}
}
}
void GHOST_WindowWin32::processWintabDisplayChangeEvent()
{
LOGCONTEXT lc_sys = {0}, lc_curr = {0};
@ -1239,48 +1230,38 @@ bool GHOST_WindowWin32::useTabletAPI(GHOST_TTabletAPI api) const
}
}
void GHOST_WindowWin32::processWintabProximityEvent(bool inRange)
void GHOST_WindowWin32::updateWintabCursorInfo()
{
if (!useTabletAPI(GHOST_kTabletWintab)) {
return;
}
// Let's see if we can initialize tablet here
if (m_wintab.info && m_wintab.context) {
AXIS Pressure, Orientation[3]; /* The maximum tablet size */
AXIS Pressure, Orientation[3];
BOOL pressureSupport = m_wintab.info(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
m_wintab.maxPressure = pressureSupport ? Pressure.axMax : 0;
BOOL tiltSupport = m_wintab.info(WTI_DEVICES, DVC_ORIENTATION, &Orientation);
/* does the tablet support azimuth ([0]) and altitude ([1]) */
/* Does the tablet support azimuth ([0]) and altitude ([1]). */
if (tiltSupport && Orientation[0].axResolution && Orientation[1].axResolution) {
m_wintab.maxAzimuth = Orientation[0].axMax;
m_wintab.maxAltitude = Orientation[1].axMax;
}
else { /* no so dont do tilt stuff */
else {
m_wintab.maxAzimuth = m_wintab.maxAltitude = 0;
}
}
m_tabletInRange = inRange;
}
void GHOST_WindowWin32::processWintabInfoChangeEvent(LPARAM lParam)
{
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)GHOST_System::getSystem();
// Update number of connected Wintab digitizers
/* Update number of connected Wintab digitizers */
if (LOWORD(lParam) == WTI_INTERFACE && HIWORD(lParam) == IFC_NDEVICES) {
m_wintab.info(WTI_INTERFACE, IFC_NDEVICES, &m_wintab.numDevices);
updateWintab((GHOST_WindowWin32 *)system->getWindowManager()->getActiveWindow() == this,
!::IsIconic(m_hWnd));
if (useTabletAPI(GHOST_kTabletWintab)) {
setWintabEnabled(true);
}
}
}
GHOST_TSuccess GHOST_WindowWin32::wintabMouseToGhost(UINT cursor,
WORD physicalButton,
GHOST_TButtonMask &ghostButton)
GHOST_TButtonMask GHOST_WindowWin32::wintabMouseToGhost(UINT cursor, WORD physicalButton)
{
const WORD numButtons = 32;
BYTE logicalButtons[numButtons] = {0};
@ -1290,198 +1271,120 @@ GHOST_TSuccess GHOST_WindowWin32::wintabMouseToGhost(UINT cursor,
m_wintab.info(WTI_CURSORS + cursor, CSR_SYSBTNMAP, &systemButtons);
if (physicalButton >= numButtons) {
return GHOST_kFailure;
return GHOST_kButtonMaskNone;
}
BYTE lb = logicalButtons[physicalButton];
if (lb >= numButtons) {
return GHOST_kFailure;
return GHOST_kButtonMaskNone;
}
switch (systemButtons[lb]) {
case SBN_LCLICK:
ghostButton = GHOST_kButtonMaskLeft;
return GHOST_kSuccess;
return GHOST_kButtonMaskLeft;
case SBN_RCLICK:
ghostButton = GHOST_kButtonMaskRight;
return GHOST_kSuccess;
return GHOST_kButtonMaskRight;
case SBN_MCLICK:
ghostButton = GHOST_kButtonMaskMiddle;
return GHOST_kSuccess;
return GHOST_kButtonMaskMiddle;
default:
return GHOST_kFailure;
return GHOST_kButtonMaskNone;
}
}
GHOST_TSuccess GHOST_WindowWin32::getWintabInfo(std::vector<GHOST_WintabInfoWin32> &outWintabInfo)
{
if (!useTabletAPI(GHOST_kTabletWintab)) {
return GHOST_kFailure;
}
if (!(m_wintab.packetsGet && m_wintab.context)) {
if (!(useTabletAPI(GHOST_kTabletWintab) && m_wintab.packetsGet && m_wintab.context)) {
return GHOST_kFailure;
}
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)GHOST_System::getSystem();
updateWintabEvents();
const int numPackets = m_wintab.packetsGet(
m_wintab.context, m_wintab.pkts.size(), m_wintab.pkts.data());
outWintabInfo.resize(numPackets);
auto &pendingEvents = m_wintab.pendingEvents;
size_t pendingEventSize = pendingEvents.size();
outWintabInfo.resize(pendingEventSize);
for (int i = 0; i < numPackets; i++) {
PACKET pkt = m_wintab.pkts[i];
GHOST_WintabInfoWin32 &out = outWintabInfo[i];
for (int i = 0; i < pendingEventSize; i++) {
PACKET pkt = pendingEvents.front();
pendingEvents.pop();
GHOST_TabletData tabletData = GHOST_TABLET_DATA_NONE;
switch (pkt.pkCursor % 3) { /* % 3 for multiple devices ("DualTrack") */
out.tabletData = GHOST_TABLET_DATA_NONE;
/* % 3 for multiple devices ("DualTrack"). */
switch (pkt.pkCursor % 3) {
case 0:
tabletData.Active = GHOST_kTabletModeNone; /* puck - not yet supported */
/* Puck - processed as mouse. */
out.tabletData.Active = GHOST_kTabletModeNone;
break;
case 1:
tabletData.Active = GHOST_kTabletModeStylus; /* stylus */
out.tabletData.Active = GHOST_kTabletModeStylus;
break;
case 2:
tabletData.Active = GHOST_kTabletModeEraser; /* eraser */
out.tabletData.Active = GHOST_kTabletModeEraser;
break;
}
out.x = pkt.pkX;
out.y = pkt.pkY;
if (m_wintab.maxPressure > 0) {
tabletData.Pressure = (float)pkt.pkNormalPressure / (float)m_wintab.maxPressure;
out.tabletData.Pressure = (float)pkt.pkNormalPressure / (float)m_wintab.maxPressure;
}
if ((m_wintab.maxAzimuth > 0) && (m_wintab.maxAltitude > 0)) {
ORIENTATION ort = pkt.pkOrientation;
float vecLen;
float altRad, azmRad; /* in radians */
float altRad, azmRad; /* In radians. */
/*
* from the wintab spec:
* orAzimuth Specifies the clockwise rotation of the
* cursor about the z axis through a full circular range.
* From the wintab spec:
* orAzimuth: Specifies the clockwise rotation of the cursor about the z axis through a
* full circular range.
* orAltitude: Specifies the angle with the x-y plane through a signed, semicircular range.
* Positive values specify an angle upward toward the positive z axis; negative values
* specify an angle downward toward the negative z axis.
*
* orAltitude Specifies the angle with the x-y plane
* through a signed, semicircular range. Positive values
* specify an angle upward toward the positive z axis;
* negative values specify an angle downward toward the negative z axis.
*
* wintab.h defines .orAltitude as a UINT but documents .orAltitude
* as positive for upward angles and negative for downward angles.
* WACOM uses negative altitude values to show that the pen is inverted;
* therefore we cast .orAltitude as an (int) and then use the absolute value.
* wintab.h defines orAltitude as a UINT but documents orAltitude as positive for upward
* angles and negative for downward angles. WACOM uses negative altitude values to show that
* the pen is inverted; therefore we cast orAltitude as an (int) and then use the absolute
* value.
*/
/* convert raw fixed point data to radians */
/* Convert raw fixed point data to radians. */
altRad = (float)((fabs((float)ort.orAltitude) / (float)m_wintab.maxAltitude) * M_PI / 2.0);
azmRad = (float)(((float)ort.orAzimuth / (float)m_wintab.maxAzimuth) * M_PI * 2.0);
/* find length of the stylus' projected vector on the XY plane */
/* Find length of the stylus' projected vector on the XY plane. */
vecLen = cos(altRad);
/* from there calculate X and Y components based on azimuth */
tabletData.Xtilt = sin(azmRad) * vecLen;
tabletData.Ytilt = (float)(sin(M_PI / 2.0 - azmRad) * vecLen);
/* From there calculate X and Y components based on azimuth. */
out.tabletData.Xtilt = sin(azmRad) * vecLen;
out.tabletData.Ytilt = (float)(sin(M_PI / 2.0 - azmRad) * vecLen);
}
outWintabInfo[i].x = pkt.pkX;
outWintabInfo[i].y = pkt.pkY;
/* Some Wintab libraries don't handle relative button input correctly, so we track button
* presses manually. Examples include Wacom's Bamboo modifying button events in the queue when
* peeked, or missing events when entering the window when the context is not on top. */
DWORD buttonsChanged = m_wintab.sysButtonsPressed ^ pkt.pkButtons;
/* Find the index for the changed button from the button map. */
WORD physicalButton = 0;
for (DWORD diff = (unsigned)buttonsChanged >> 1; diff > 0; diff = (unsigned)diff >> 1) {
physicalButton++;
out.button = wintabMouseToGhost(pkt.pkCursor, LOWORD(pkt.pkButtons));
switch (HIWORD(pkt.pkButtons)) {
case TBN_NONE:
out.type = GHOST_kEventCursorMove;
break;
case TBN_DOWN:
out.type = GHOST_kEventButtonDown;
break;
case TBN_UP:
out.type = GHOST_kEventButtonUp;
break;
}
if (buttonsChanged &&
wintabMouseToGhost(pkt.pkCursor, physicalButton, outWintabInfo[i].button)) {
if (buttonsChanged & pkt.pkButtons) {
outWintabInfo[i].type = GHOST_kEventButtonDown;
}
else {
outWintabInfo[i].type = GHOST_kEventButtonUp;
}
}
else {
outWintabInfo[i].type = GHOST_kEventCursorMove;
}
out.time = system->tickCountToMillis(pkt.pkTime);
}
m_wintab.sysButtonsPressed = pkt.pkButtons;
outWintabInfo[i].time = system->millisSinceStart(pkt.pkTime);
outWintabInfo[i].tabletData = tabletData;
if (!outWintabInfo.empty()) {
lastTabletData = outWintabInfo.back().tabletData;
}
return GHOST_kSuccess;
}
void GHOST_WindowWin32::updateWintabEvents()
GHOST_TabletData GHOST_WindowWin32::getLastTabletData()
{
readWintabEvents();
// When a Wintab device is used to leave window focus, some of it's packets are periodically not
// queued in time to be flushed. Reading packets needs to occur before expiring packets to clear
// these from the queue.
expireWintabEvents();
}
void GHOST_WindowWin32::updateWintabEventsSyncTime()
{
readWintabEvents();
if (!m_wintab.pendingEvents.empty()) {
auto lastEvent = m_wintab.pendingEvents.back();
m_wintab.sysTimeOffset = ::GetTickCount() - lastEvent.pkTime;
}
expireWintabEvents();
}
void GHOST_WindowWin32::readWintabEvents()
{
if (!(m_wintab.packetsGet && m_wintab.context)) {
return;
}
auto &pendingEvents = m_wintab.pendingEvents;
/* Get new packets. */
const int numPackets = m_wintab.packetsGet(
m_wintab.context, m_wintab.pkts.size(), m_wintab.pkts.data());
for (int i = 0; i < numPackets; i++) {
pendingEvents.push(m_wintab.pkts[i]);
}
}
/* Wintab (per documentation but may vary with implementation) does not update when its event
* buffer is full. This is an issue because we need some synchronization point between Wintab
* events and Win32 events, so we can't drain and process the queue immediately. We need to
* associate Wintab mouse events to Win32 mouse events because Wintab buttons are modal (a button
* associated to left click is not always a left click) and there's no way to reconstruct their
* mode from the Wintab API alone. There is no guaranteed ordering between Wintab and Win32 mouse
* events and no documented time stamp shared between the two, so we synchronize on mouse button
* events. */
void GHOST_WindowWin32::expireWintabEvents()
{
auto &pendingEvents = m_wintab.pendingEvents;
DWORD currTime = ::GetTickCount() - m_wintab.sysTimeOffset;
DWORD millisTimeout = 300;
while (!pendingEvents.empty()) {
DWORD pkTime = pendingEvents.front().pkTime;
if (currTime > pkTime + millisTimeout) {
pendingEvents.pop();
}
else {
break;
}
}
return lastTabletData;
}
GHOST_TUns16 GHOST_WindowWin32::getDPIHint()

View File

@ -41,7 +41,7 @@
// PACKETDATA and PACKETMODE modify structs in pktdef.h, so make sure they come first
#define PACKETDATA \
(PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR | PK_X | PK_Y | PK_TIME)
#define PACKETMODE 0
#define PACKETMODE PK_BUTTONS
#include <pktdef.h>
class GHOST_SystemWin32;
@ -437,13 +437,6 @@ class GHOST_WindowWin32 : public GHOST_Window {
HCURSOR getStandardCursor(GHOST_TStandardCursor shape) const;
void loadCursor(bool visible, GHOST_TStandardCursor cursorShape) const;
/**
* Handle setup and switch between Wintab and Pointer APIs.
* \param active: Whether the window is or will be in an active state.
* \param visible: Whether the window is currently (or will be) visible).
*/
void updateWintab(bool active, bool visible);
/**
* Query whether given tablet API should be used.
* \param api: Tablet API to test.
@ -461,16 +454,27 @@ class GHOST_WindowWin32 : public GHOST_Window {
WPARAM wParam,
LPARAM lParam);
/**
* Enables or disables Wintab context.
* \param enable: Whether the context should be enabled.
*/
void setWintabEnabled(bool enable);
/**
* Changes Wintab context overlap.
* \param overlap: Whether context should be brought to top of overlap order.
*/
void setWintabOverlap(bool overlap);
/**
* Handle Wintab coordinate changes when DisplayChange events occur.
*/
void processWintabDisplayChangeEvent();
/**
* Set tablet details when a cursor enters range.
* \param inRange: Whether the Wintab device is in tracking range.
* Updates cached Wintab properties for current cursor.
*/
void processWintabProximityEvent(bool inRange);
void updateWintabCursorInfo();
/**
* Handle Wintab info changes such as change in number of connected tablets.
@ -486,14 +490,10 @@ class GHOST_WindowWin32 : public GHOST_Window {
GHOST_TSuccess getWintabInfo(std::vector<GHOST_WintabInfoWin32> &outWintabInfo);
/**
* Updates pending Wintab events and syncs Wintab time with OS time.
* Get the most recent tablet data.
* \return Most recent tablet data.
*/
void updateWintabEventsSyncTime();
/**
* Updates pending Wintab events.
*/
void updateWintabEvents();
GHOST_TabletData getLastTabletData();
GHOST_TSuccess beginFullScreen() const
{
@ -507,24 +507,8 @@ class GHOST_WindowWin32 : public GHOST_Window {
GHOST_TUns16 getDPIHint() override;
/**
* Get whether there are currently any mouse buttons pressed.
* \return True if there are any currently pressed mouse buttons.
*/
bool getMousePressed() const;
/**
* Get if there are currently pressed Wintab buttons associated to a Windows mouse button press.
* \return True if there are currently any pressed Wintab buttons associated to a Windows
* mouse button press.
*/
bool wintabSysButPressed() const;
/**
* Register a Wintab button has been associated to a Windows mouse button press.
* \param event: Whether the button was pressed or released.
*/
void updateWintabSysBut(GHOST_MouseCaptureEventWin32 event);
/** Whether the mouse is either over or captured by the window. */
bool m_mousePresent;
/** Whether a tablet stylus is being tracked. */
bool m_tabletInRange;
@ -582,28 +566,28 @@ class GHOST_WindowWin32 : public GHOST_Window {
int hotY,
bool canInvertColor);
/** Pointer to system */
/** Pointer to system. */
GHOST_SystemWin32 *m_system;
/** Pointer to COM IDropTarget implementor */
/** Pointer to COM IDropTarget implementor. */
GHOST_DropTargetWin32 *m_dropTarget;
/** Window handle. */
HWND m_hWnd;
/** Device context handle. */
HDC m_hDC;
/** Flag for if window has captured the mouse */
/** Flag for if window has captured the mouse. */
bool m_hasMouseCaptured;
/** Flag if an operator grabs the mouse with WM_cursor_grab_enable/ungrab()
* Multiple grabs must be released with a single ungrab */
/** Flag if an operator grabs the mouse with WM_cursor_grab_enable/ungrab().
* Multiple grabs must be released with a single ungrab. */
bool m_hasGrabMouse;
/** Count of number of pressed buttons */
/** Count of number of pressed buttons. */
int m_nPressedButtons;
/** HCURSOR structure of the custom cursor */
/** HCURSOR structure of the custom cursor. */
HCURSOR m_customCursor;
/** request GL context aith alpha channel */
/** Request GL context aith alpha channel. */
bool m_wantAlphaBackground;
/** ITaskbarList3 structure for progress bar*/
/** ITaskbarList3 structure for progress bar. */
ITaskbarList3 *m_Bar;
static const wchar_t *s_windowClassName;
@ -626,42 +610,31 @@ class GHOST_WindowWin32 : public GHOST_Window {
GHOST_WIN32_WTEnable enable = NULL;
GHOST_WIN32_WTOverlap overlap = NULL;
/** Stores the Tablet context if detected Tablet features using WinTab.dll */
/** Stores the Tablet context if detected Tablet features using WinTab.dll. */
HCTX context = NULL;
/** Number of connected Wintab digitizers */
/** Number of connected Wintab digitizers. */
UINT numDevices = 0;
/** Number of cursors currently in contact mapped to system buttons */
GHOST_TUns8 numSysButtons = 0;
/** Cursors currently in contact mapped to system buttons */
DWORD sysButtonsPressed = 0;
DWORD sysTimeOffset = 0;
LONG maxPressure = 0;
LONG maxAzimuth = 0, maxAltitude = 0;
/** Reusable buffer to read in Wintab Packets. */
std::vector<PACKET> pkts;
/** Queue of packets to process. */
std::queue<PACKET> pendingEvents;
} m_wintab;
/** Most recent tablet data. */
GHOST_TabletData lastTabletData = GHOST_TABLET_DATA_NONE;
/**
* Wintab setup.
*/
void initializeWintab();
void readWintabEvents();
void expireWintabEvents();
/**
* Convert Wintab system mapped (mouse) buttons into Ghost button mask.
* \param cursor: The Wintab cursor associated to the button.
* \param physicalButton: The physical button ID to inspect.
* \param buttonMask: Return pointer for button found.
* \return Whether an associated button was found.
* \return The system mapped button.
*/
GHOST_TSuccess wintabMouseToGhost(UINT cursor,
WORD physicalButton,
GHOST_TButtonMask &buttonMask);
GHOST_TButtonMask wintabMouseToGhost(UINT cursor, WORD physicalButton);
GHOST_TWindowState m_normal_state;

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

@ -558,6 +558,7 @@ def dump_py_messages_from_files(msgs, reports, files, settings):
"msgid": ((("msgctxt",), _ctxt_to_ctxt),
),
"message": (),
"heading": (),
}
context_kw_set = {}

View File

@ -504,6 +504,7 @@ MO_FILE_NAME = DOMAIN + ".mo"
# Where to search for py files that may contain ui strings (relative to one of the 'resource_path' of Blender).
CUSTOM_PY_UI_FILES = [
os.path.join("scripts", "startup", "bl_ui"),
os.path.join("scripts", "startup", "bl_operators"),
os.path.join("scripts", "modules", "rna_prop_ui.py"),
]

View File

@ -38,6 +38,7 @@ class SpellChecker:
"boolean", "booleans",
"chamfer",
"couldn", # couldn't
"customizable",
"decrement",
"derivate",
"deterministically",

View File

@ -296,13 +296,10 @@ def bake_action_iter(
pbone.keyframe_insert("rotation_axis_angle", index=-1, frame=f, group=name)
else: # euler, XYZ, ZXY etc
if euler_prev is not None:
euler = pbone.rotation_euler.copy()
euler.make_compatible(euler_prev)
euler = pbone.matrix_basis.to_euler(obj.rotation_mode, euler_prev)
pbone.rotation_euler = euler
euler_prev = euler
del euler
else:
euler_prev = pbone.rotation_euler.copy()
euler_prev = pbone.rotation_euler.copy()
pbone.keyframe_insert("rotation_euler", index=-1, frame=f, group=name)
pbone.keyframe_insert("scale", index=-1, frame=f, group=name)

View File

@ -130,7 +130,7 @@ class Prefs(bpy.types.KeyConfigPreferences):
description=(
"The action when Middle-Mouse dragging in the viewport. "
"Shift-Middle-Mouse is used for the other action. "
"This applies to Track-Pad as well"
"This applies to trackpad as well"
),
update=update_fn,
)

View File

@ -347,7 +347,7 @@ class ClearUselessActions(Operator):
class UpdateAnimatedTransformConstraint(Operator):
"""Update fcurves/drivers affecting Transform constraints (use it with files from 2.70 and earlier)"""
"""Update f-curves/drivers affecting Transform constraints (use it with files from 2.70 and earlier)"""
bl_idname = "anim.update_animated_transform_constraints"
bl_label = "Update Animated Transform Constraints"
bl_options = {'REGISTER', 'UNDO'}

View File

@ -181,23 +181,20 @@ class MeshMirrorUV(Operator):
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
if total_duplicates and total_no_active_UV:
self.report({'WARNING'}, "%d %s with no active UV layer. "
"%d duplicates found in %d %s, mirror may be incomplete."
self.report({'WARNING'},
"%d mesh(es) with no active UV layer, "
"%d duplicates found in %d mesh(es), mirror may be incomplete"
% (total_no_active_UV,
"mesh" if total_no_active_UV == 1 else "meshes",
total_duplicates,
meshes_with_duplicates,
"mesh" if meshes_with_duplicates == 1 else "meshes"))
meshes_with_duplicates))
elif total_no_active_UV:
self.report({'WARNING'}, "%d %s with no active UV layer."
% (total_no_active_UV,
"mesh" if total_no_active_UV == 1 else "meshes"))
self.report({'WARNING'},
"%d mesh(es) with no active UV layer"
% (total_no_active_UV,))
elif total_duplicates:
self.report({'WARNING'}, "%d duplicates found in %d %s,"
" mirror may be incomplete."
% (total_duplicates,
meshes_with_duplicates,
"mesh" if meshes_with_duplicates == 1 else "meshes"))
self.report({'WARNING'},
"%d duplicates found in %d mesh(es), mirror may be incomplete"
% (total_duplicates, meshes_with_duplicates))
return {'FINISHED'}

View File

@ -566,7 +566,7 @@ class JoinUVs(Operator):
uv_other = mesh_other.uv_layers.active
if not uv_other:
self.report({'ERROR'}, "Could not add "
"a new UV map tp object "
"a new UV map to object "
"'%s' (Mesh '%s')\n"
% (obj_other.name,
mesh_other.name,

View File

@ -254,7 +254,7 @@ class ExecutePreset(Operator):
ext = splitext(filepath)[1].lower()
if ext not in {".py", ".xml"}:
self.report({'ERROR'}, "unknown filetype: %r" % ext)
self.report({'ERROR'}, "Unknown file type: %r" % ext)
return {'CANCELLED'}
if hasattr(preset_class, "reset_cb"):

View File

@ -80,7 +80,7 @@ class SequencerCrossfadeSounds(Operator):
class SequencerSplitMulticam(Operator):
"""Split multi-cam strip and select camera"""
"""Split multicam strip and select camera"""
bl_idname = "sequencer.split_multicam"
bl_label = "Split Multicam"
@ -242,7 +242,7 @@ class SequencerFadesAdd(Operator):
sequence.invalidate_cache('COMPOSITE')
sequence_string = "sequence" if len(faded_sequences) == 1 else "sequences"
self.report({'INFO'}, "Added fade animation to %d %s." % (len(faded_sequences), sequence_string))
self.report({'INFO'}, "Added fade animation to %d %s" % (len(faded_sequences), sequence_string))
return {'FINISHED'}
def calculate_fade_duration(self, context, sequence):

View File

@ -868,7 +868,7 @@ class PREFERENCES_OT_addon_show(Operator):
# Note: shares some logic with PREFERENCES_OT_addon_install
# but not enough to de-duplicate. Fixes here may apply to both.
class PREFERENCES_OT_app_template_install(Operator):
"""Install an application-template"""
"""Install an application template"""
bl_idname = "preferences.app_template_install"
bl_label = "Install Template from File..."

View File

@ -635,14 +635,14 @@ class LightMapPack(Operator):
)
PREF_IMG_PX_SIZE: IntProperty(
name="Image Size",
description="Width and Height for the new image",
description="Width and height for the new image",
min=64, max=5000,
default=512,
)
# UV Packing...
PREF_BOX_DIV: IntProperty(
name="Pack Quality",
description="Pre Packing before the complex boxpack",
description="Pre-packing before the complex boxpack",
min=1, max=48,
default=12,
)

View File

@ -834,7 +834,7 @@ class WM_OT_context_modal_mouse(Operator):
class WM_OT_url_open(Operator):
"""Open a website in the web-browser"""
"""Open a website in the web browser"""
bl_idname = "wm.url_open"
bl_label = ""
bl_options = {'INTERNAL'}
@ -851,7 +851,7 @@ class WM_OT_url_open(Operator):
class WM_OT_url_open_preset(Operator):
"""Open a preset website in the web-browser"""
"""Open a preset website in the web browser"""
bl_idname = "wm.url_open_preset"
bl_label = "Open Preset Website"
bl_options = {'INTERNAL'}
@ -893,7 +893,7 @@ class WM_OT_url_open_preset(Operator):
(('BUG', "Bug",
"Report a bug with pre-filled version information"),
_url_from_bug),
(('BUG_ADDON', "Add-On Bug",
(('BUG_ADDON', "Add-on Bug",
"Report a bug in an add-on"),
_url_from_bug_addon),
(('RELEASE_NOTES', "Release Notes",
@ -1175,7 +1175,7 @@ rna_use_soft_limits = BoolProperty(
rna_is_overridable_library = BoolProperty(
name="Is Library Overridable",
description="Allow the property to be overridden when the Data-Block is linked",
description="Allow the property to be overridden when the data-block is linked",
default=False,
)
@ -1604,7 +1604,7 @@ class WM_OT_sysinfo(Operator):
class WM_OT_operator_cheat_sheet(Operator):
"""List all the Operators in a text-block, useful for scripting"""
"""List all the operators in a text-block, useful for scripting"""
bl_idname = "wm.operator_cheat_sheet"
bl_label = "Operator Cheat Sheet"
@ -1625,7 +1625,7 @@ class WM_OT_operator_cheat_sheet(Operator):
textblock = bpy.data.texts.new("OperatorList.txt")
textblock.write('# %d Operators\n\n' % tot)
textblock.write('\n'.join(op_strings))
self.report({'INFO'}, "See OperatorList.txt textblock")
self.report({'INFO'}, "See OperatorList.txt text block")
return {'FINISHED'}
@ -1717,7 +1717,7 @@ class WM_OT_tool_set_by_id(Operator):
tool_settings.workspace_tool_type = 'FALLBACK'
return {'FINISHED'}
else:
self.report({'WARNING'}, "Tool %r not found for space %r." % (self.name, space_type))
self.report({'WARNING'}, "Tool %r not found for space %r" % (self.name, space_type))
return {'CANCELLED'}
@ -1726,7 +1726,7 @@ class WM_OT_tool_set_by_index(Operator):
bl_idname = "wm.tool_set_by_index"
bl_label = "Set Tool by Index"
index: IntProperty(
name="Index in toolbar",
name="Index in Toolbar",
default=0,
)
cycle: BoolProperty(
@ -1737,7 +1737,7 @@ class WM_OT_tool_set_by_index(Operator):
)
expand: BoolProperty(
description="Include tool sub-groups",
description="Include tool subgroups",
default=True,
)
@ -2163,13 +2163,13 @@ class WM_OT_batch_rename(Operator):
object_data_type_attrs_map = {
'MESH': ("meshes", "Mesh(es)"),
'CURVE': ("curves", "Curve(s)"),
'META': ("metaballs", "MetaBall(s)"),
'META': ("metaballs", "Metaball(s)"),
'ARMATURE': ("armatures", "Armature(s)"),
'LATTICE': ("lattices", "Lattice(s)"),
'GPENCIL': ("grease_pencils", "Grease Pencil(s)"),
'CAMERA': ("cameras", "Camera(s)"),
'SPEAKER': ("speakers", "Speaker(s)"),
'LIGHT_PROBE': ("light_probes", "LightProbe(s)"),
'LIGHT_PROBE': ("light_probes", "Light Probe(s)"),
}
# Finish with space types.

View File

@ -867,7 +867,7 @@ class GreasePencilLayerDisplayPanel:
class GreasePencilFlipTintColors(Operator):
bl_label = "Flip Colors"
bl_idname = "gpencil.tint_flip"
bl_description = "Switch Tint colors"
bl_description = "Switch tint colors"
def execute(self, context):
try:

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

@ -589,7 +589,7 @@ class ASSETBROWSER_PT_metadata(asset_utils.AssetBrowserPanel, Panel):
active_asset = asset_utils.SpaceAssetInfo.get_active_asset(context)
if not active_file or not active_asset:
layout.label(text="No asset selected.", icon='INFO')
layout.label(text="No asset selected", icon='INFO')
return
# If the active file is an ID, use its name directly so renaming is possible from right here.

View File

@ -46,6 +46,8 @@ class PROPERTIES_HT_header(Header):
layout.separator_spacer()
layout.popover(panel="PROPERTIES_PT_options", text="")
class PROPERTIES_PT_navigation_bar(Panel):
bl_space_type = 'PROPERTIES'
@ -69,9 +71,25 @@ class PROPERTIES_PT_navigation_bar(Panel):
layout.prop_tabs_enum(view, "context", icon_only=True)
class PROPERTIES_PT_options(Panel):
bl_space_type = 'PROPERTIES'
bl_region_type = 'HEADER'
bl_label = 'Options'
def draw(self, context):
layout = self.layout
space = context.space_data
col = layout.column()
col.label(text="Sync with Outliner")
col.row().prop(space, "outliner_sync", expand=True)
classes = (
PROPERTIES_HT_header,
PROPERTIES_PT_navigation_bar,
PROPERTIES_PT_options,
)
if __name__ == "__main__": # only for live edit.

View File

@ -1424,7 +1424,7 @@ class _defs_sculpt:
return dict(
idname="builtin.mask_by_color",
label="Mask By Color",
label="Mask by Color",
icon="ops.sculpt.mask_by_color",
widget=None,
keymap=(),

View File

@ -1437,7 +1437,7 @@ class USERPREF_PT_saveload_file_browser(SaveLoadPanel, CenterAlignMixIn, Panel):
col.prop(paths, "use_filter_files")
col = layout.column(heading="Hide")
col.prop(paths, "show_hidden_files_datablocks", text="Dot File & Datablocks")
col.prop(paths, "show_hidden_files_datablocks", text="Dot File & Data-Blocks")
col.prop(paths, "hide_recent_locations", text="Recent Locations")
col.prop(paths, "hide_system_bookmarks", text="System Bookmarks")

View File

@ -957,7 +957,7 @@ class VIEW3D_MT_transform(VIEW3D_MT_transform_base, Menu):
# generic...
layout = self.layout
if context.mode == 'EDIT_MESH':
layout.operator("transform.shrink_fatten", text="Shrink Fatten")
layout.operator("transform.shrink_fatten", text="Shrink/Fatten")
layout.operator("transform.skin_resize")
elif context.mode == 'EDIT_CURVE':
layout.operator("transform.transform", text="Radius").mode = 'CURVE_SHRINKFATTEN'
@ -5091,7 +5091,7 @@ class VIEW3D_MT_edit_gpencil_transform(Menu):
layout.operator("transform.bend", text="Bend")
layout.operator("transform.shear", text="Shear")
layout.operator("transform.tosphere", text="To Sphere")
layout.operator("transform.transform", text="Shrink Fatten").mode = 'GPENCIL_SHRINKFATTEN'
layout.operator("transform.transform", text="Shrink/Fatten").mode = 'GPENCIL_SHRINKFATTEN'
class VIEW3D_MT_edit_gpencil_showhide(Menu):
@ -7044,7 +7044,7 @@ class VIEW3D_MT_gpencil_edit_context_menu(Menu):
col.operator("transform.bend", text="Bend")
col.operator("transform.shear", text="Shear")
col.operator("transform.tosphere", text="To Sphere")
col.operator("transform.transform", text="Shrink Fatten").mode = 'GPENCIL_SHRINKFATTEN'
col.operator("transform.transform", text="Shrink/Fatten").mode = 'GPENCIL_SHRINKFATTEN'
col.separator()
@ -7088,7 +7088,7 @@ class VIEW3D_MT_gpencil_edit_context_menu(Menu):
col.separator()
col.operator("gpencil.stroke_smooth", text="Smooth Stroke").only_selected = False
col.operator("transform.transform", text="Shrink Fatten").mode = 'GPENCIL_SHRINKFATTEN'
col.operator("transform.transform", text="Shrink/Fatten").mode = 'GPENCIL_SHRINKFATTEN'
col.separator()

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

@ -201,7 +201,7 @@ void BKE_id_free(struct Main *bmain, void *idv);
void BKE_id_free_us(struct Main *bmain, void *idv) ATTR_NONNULL();
void BKE_id_delete(struct Main *bmain, void *idv) ATTR_NONNULL();
void BKE_id_multi_tagged_delete(struct Main *bmain) ATTR_NONNULL();
size_t BKE_id_multi_tagged_delete(struct Main *bmain) ATTR_NONNULL();
void BKE_libblock_management_main_add(struct Main *bmain, void *idv);
void BKE_libblock_management_main_remove(struct Main *bmain, void *idv);

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

@ -645,9 +645,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

@ -1421,125 +1421,147 @@ static NlaEvalChannel *nlaevalchan_verify(PointerRNA *ptr, NlaEvalData *nlaeval,
/* ---------------------- */
/* accumulate the old and new values of a channel according to mode and influence */
static float nla_blend_value(int blendmode, float old_value, float value, float inf)
/* Blend the lower nla stack value and upper strip value of a channel according to mode and
* influence. */
static float nla_blend_value(const int blendmode,
const float lower_value,
const float strip_value,
const float influence)
{
/* Optimization: no need to try applying if there is no influence. */
if (IS_EQF(inf, 0.0f)) {
return old_value;
if (IS_EQF(influence, 0.0f)) {
return lower_value;
}
/* perform blending */
/* Perform blending. */
switch (blendmode) {
case NLASTRIP_MODE_ADD:
/* simply add the scaled value on to the stack */
return old_value + (value * inf);
/* Simply add the scaled value on to the stack. */
return lower_value + (strip_value * influence);
case NLASTRIP_MODE_SUBTRACT:
/* simply subtract the scaled value from the stack */
return old_value - (value * inf);
/* Simply subtract the scaled value from the stack. */
return lower_value - (strip_value * influence);
case NLASTRIP_MODE_MULTIPLY:
/* multiply the scaled value with the stack */
/* Formula Used:
* result = fac * (a * b) + (1 - fac) * a
*/
return inf * (old_value * value) + (1 - inf) * old_value;
/* Multiply the scaled value with the stack. */
return influence * (lower_value * strip_value) + (1 - influence) * lower_value;
case NLASTRIP_MODE_COMBINE:
BLI_assert(!"combine mode");
ATTR_FALLTHROUGH;
case NLASTRIP_MODE_REPLACE:
default
: /* TODO: do we really want to blend by default? it seems more uses might prefer add... */
/* do linear interpolation
* - the influence of the accumulated data (elsewhere, that is called dstweight)
* is 1 - influence, since the strip's influence is srcweight
default:
/* TODO: Do we really want to blend by default? it seems more uses might prefer add... */
/* Do linear interpolation. The influence of the accumulated data (elsewhere, that is called
* dstweight) is 1 - influence, since the strip's influence is srcweight.
*/
return old_value * (1.0f - inf) + (value * inf);
return lower_value * (1.0f - influence) + (strip_value * influence);
}
}
/* accumulate the old and new values of a channel according to mode and influence */
static float nla_combine_value(
int mix_mode, float base_value, float old_value, float value, float inf)
/* Blend the lower nla stack value and upper strip value of a channel according to mode and
* influence. */
static float nla_combine_value(const int mix_mode,
float base_value,
const float lower_value,
const float strip_value,
const float influence)
{
/* Optimization: no need to try applying if there is no influence. */
if (IS_EQF(inf, 0.0f)) {
return old_value;
/* Optimization: No need to try applying if there is no influence. */
if (IS_EQF(influence, 0.0f)) {
return lower_value;
}
/* perform blending */
/* Perform blending */
switch (mix_mode) {
case NEC_MIX_ADD:
case NEC_MIX_AXIS_ANGLE:
return old_value + (value - base_value) * inf;
return lower_value + (strip_value - base_value) * influence;
case NEC_MIX_MULTIPLY:
if (IS_EQF(base_value, 0.0f)) {
base_value = 1.0f;
}
return old_value * powf(value / base_value, inf);
return lower_value * powf(strip_value / base_value, influence);
case NEC_MIX_QUATERNION:
default:
BLI_assert(!"invalid mix mode");
return old_value;
return lower_value;
}
}
/* compute the value that would blend to the desired target value using nla_blend_value */
static bool nla_invert_blend_value(
int blend_mode, float old_value, float target_value, float influence, float *r_value)
/** \returns true if solution exists and output is written to. */
static bool nla_blend_get_inverted_strip_value(const int blendmode,
const float lower_value,
const float blended_value,
const float influence,
float *r_strip_value)
{
/** No solution if strip had 0 influence. */
if (IS_EQF(influence, 0.0f)) {
return false;
}
switch (blend_mode) {
switch (blendmode) {
case NLASTRIP_MODE_ADD:
*r_value = (target_value - old_value) / influence;
*r_strip_value = (blended_value - lower_value) / influence;
return true;
case NLASTRIP_MODE_SUBTRACT:
*r_value = (old_value - target_value) / influence;
*r_strip_value = (lower_value - blended_value) / influence;
return true;
case NLASTRIP_MODE_MULTIPLY:
if (IS_EQF(old_value, 0.0f)) {
if (IS_EQF(lower_value, 0.0f)) {
/* Resolve 0/0 to 1. */
if (IS_EQF(target_value, 0.0f)) {
*r_value = 1.0f;
if (IS_EQF(blended_value, 0.0f)) {
*r_strip_value = 1.0f;
return true;
}
/* Division by zero. */
return false;
}
else {
*r_value = (target_value - old_value) / influence / old_value + 1.0f;
return true;
}
/** Math:
*
* blended_value = inf * (lower_value * strip_value) + (1 - inf) * lower_value
* blended_value - (1 - inf) * lower_value = inf * (lower_value * strip_value)
* (blended_value - (1 - inf) * lower_value) / (inf * lower_value) = strip_value
* (blended_value - lower_value + inf * lower_value) / (inf * lower_value) = strip_value
* ((blended_value - lower_value) / (inf * lower_value)) + 1 = strip_value
*
* strip_value = ((blended_value - lower_value) / (inf * lower_value)) + 1
*/
*r_strip_value = ((blended_value - lower_value) / (influence * lower_value)) + 1.0f;
return true;
case NLASTRIP_MODE_COMBINE:
BLI_assert(!"combine mode");
ATTR_FALLTHROUGH;
case NLASTRIP_MODE_REPLACE:
default:
*r_value = (target_value - old_value) / influence + old_value;
/** Math:
*
* blended_value = lower_value * (1.0f - inf) + (strip_value * inf)
* blended_value - lower_value * (1.0f - inf) = (strip_value * inf)
* (blended_value - lower_value * (1.0f - inf)) / inf = strip_value
*
* strip_value = (blended_value - lower_value * (1.0f - inf)) / inf
*/
*r_strip_value = (blended_value - lower_value * (1.0f - influence)) / influence;
return true;
}
}
/* compute the value that would blend to the desired target value using nla_combine_value */
static bool nla_invert_combine_value(int mix_mode,
float base_value,
float old_value,
float target_value,
float influence,
float *r_value)
/** \returns true if solution exists and output is written to. */
static bool nla_combine_get_inverted_strip_value(const int mix_mode,
float base_value,
const float lower_value,
const float blended_value,
const float influence,
float *r_strip_value)
{
/* No solution if strip had no influence. */
if (IS_EQF(influence, 0.0f)) {
@ -1549,65 +1571,72 @@ static bool nla_invert_combine_value(int mix_mode,
switch (mix_mode) {
case NEC_MIX_ADD:
case NEC_MIX_AXIS_ANGLE:
*r_value = base_value + (target_value - old_value) / influence;
*r_strip_value = base_value + (blended_value - lower_value) / influence;
return true;
case NEC_MIX_MULTIPLY:
if (IS_EQF(base_value, 0.0f)) {
base_value = 1.0f;
}
if (IS_EQF(old_value, 0.0f)) {
/* Divison by zero. */
if (IS_EQF(lower_value, 0.0f)) {
/* Resolve 0/0 to 1. */
if (IS_EQF(target_value, 0.0f)) {
*r_value = base_value;
if (IS_EQF(blended_value, 0.0f)) {
*r_strip_value = base_value;
return true;
}
/* Division by zero. */
return false;
}
*r_value = base_value * powf(target_value / old_value, 1.0f / influence);
*r_strip_value = base_value * powf(blended_value / lower_value, 1.0f / influence);
return true;
case NEC_MIX_QUATERNION:
default:
BLI_assert(!"invalid mix mode");
return false;
}
}
/* accumulate quaternion channels for Combine mode according to influence */
static void nla_combine_quaternion(const float old_values[4],
const float values[4],
float influence,
float result[4])
/** Accumulate quaternion channels for Combine mode according to influence.
* \returns blended_value = lower_values @ strip_values^infl
*/
static void nla_combine_quaternion(const float lower_values[4],
const float strip_values[4],
const float influence,
float r_blended_value[4])
{
float tmp_old[4], tmp_new[4];
float tmp_lower[4], tmp_strip_values[4];
normalize_qt_qt(tmp_old, old_values);
normalize_qt_qt(tmp_new, values);
normalize_qt_qt(tmp_lower, lower_values);
normalize_qt_qt(tmp_strip_values, strip_values);
pow_qt_fl_normalized(tmp_new, influence);
mul_qt_qtqt(result, tmp_old, tmp_new);
pow_qt_fl_normalized(tmp_strip_values, influence);
mul_qt_qtqt(r_blended_value, tmp_lower, tmp_strip_values);
}
/* invert accumulation of quaternion channels for Combine mode according to influence */
static bool nla_invert_combine_quaternion(const float old_values[4],
const float values[4],
float influence,
float result[4])
/** \returns true if solution exists and output written to. */
static bool nla_combine_quaternion_get_inverted_strip_values(const float lower_values[4],
const float blended_values[4],
const float influence,
float r_strip_values[4])
{
/* blended_value = lower_values @ r_strip_values^infl
* inv(lower_values) @ blended_value = r_strip_values^infl
* (inv(lower_values) @ blended_value) ^ (1/inf) = r_strip_values
*
* Returns: r_strip_values = (inv(lower_values) @ blended_value) ^ (1/inf) */
if (IS_EQF(influence, 0.0f)) {
return false;
}
float tmp_old[4], tmp_new[4];
float tmp_lower[4], tmp_blended[4];
normalize_qt_qt(tmp_old, old_values);
normalize_qt_qt(tmp_new, values);
invert_qt_normalized(tmp_old);
normalize_qt_qt(tmp_lower, lower_values);
normalize_qt_qt(tmp_blended, blended_values);
invert_qt_normalized(tmp_lower);
mul_qt_qtqt(result, tmp_old, tmp_new);
pow_qt_fl_normalized(result, 1.0f / influence);
mul_qt_qtqt(r_strip_values, tmp_lower, tmp_blended);
pow_qt_fl_normalized(r_strip_values, 1.0f / influence);
return true;
}
@ -2442,8 +2471,9 @@ NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(
ctx = MEM_callocN(sizeof(*ctx), "NlaKeyframingContext");
ctx->adt = adt;
nlaeval_init(&ctx->nla_channels);
animsys_evaluate_nla(&ctx->nla_channels, ptr, adt, anim_eval_context, flush_to_original, ctx);
nlaeval_init(&ctx->lower_eval_data);
animsys_evaluate_nla(
&ctx->lower_eval_data, ptr, adt, anim_eval_context, flush_to_original, ctx);
BLI_assert(ELEM(ctx->strip.act, NULL, adt->action));
BLI_addtail(cache, ctx);
@ -2504,44 +2534,51 @@ bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
.ptr = *prop_ptr,
.prop = prop,
};
NlaEvalData *nlaeval = &context->nla_channels;
NlaEvalChannel *nec = nlaevalchan_verify_key(nlaeval, NULL, &key);
/**
* Remove lower NLA stack effects.
*
* Using the tweak strip's blended result and the lower snapshot value, we can solve for the
* tweak strip value it must evaluate to.
*/
NlaEvalData *const lower_eval_data = &context->lower_eval_data;
NlaEvalChannel *const lower_nec = nlaevalchan_verify_key(lower_eval_data, NULL, &key);
if (nec->base_snapshot.length != count) {
if ((lower_nec->base_snapshot.length != count)) {
BLI_assert(!"invalid value count");
return false;
}
/* Invert the blending operation to compute the desired key values. */
NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_find_channel(&nlaeval->eval_snapshot,
nec);
/* Invert the blending operation to compute the desired strip values. */
NlaEvalChannelSnapshot *const lower_nec_snapshot = nlaeval_snapshot_find_channel(
&lower_eval_data->eval_snapshot, lower_nec);
float *old_values = nec_snapshot->values;
float *lower_values = lower_nec_snapshot->values;
if (blend_mode == NLASTRIP_MODE_COMBINE) {
/* Quaternion combine handles all sub-channels as a unit. */
if (nec->mix_mode == NEC_MIX_QUATERNION) {
if (lower_nec->mix_mode == NEC_MIX_QUATERNION) {
if (r_force_all == NULL) {
return false;
}
*r_force_all = true;
if (!nla_invert_combine_quaternion(old_values, values, influence, values)) {
if (!nla_combine_quaternion_get_inverted_strip_values(
lower_values, values, influence, values)) {
return false;
}
}
else {
float *base_values = nec->base_snapshot.values;
float *base_values = lower_nec->base_snapshot.values;
for (int i = 0; i < count; i++) {
if (ELEM(index, i, -1)) {
if (!nla_invert_combine_value(nec->mix_mode,
base_values[i],
old_values[i],
values[i],
influence,
&values[i])) {
if (!nla_combine_get_inverted_strip_value(lower_nec->mix_mode,
base_values[i],
lower_values[i],
values[i],
influence,
&values[i])) {
return false;
}
}
@ -2551,7 +2588,8 @@ bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
else {
for (int i = 0; i < count; i++) {
if (ELEM(index, i, -1)) {
if (!nla_invert_blend_value(blend_mode, old_values[i], values[i], influence, &values[i])) {
if (!nla_blend_get_inverted_strip_value(
blend_mode, lower_values[i], values[i], influence, &values[i])) {
return false;
}
}
@ -2568,7 +2606,7 @@ void BKE_animsys_free_nla_keyframing_context_cache(struct ListBase *cache)
{
LISTBASE_FOREACH (NlaKeyframingContext *, ctx, cache) {
MEM_SAFE_FREE(ctx->eval_strip);
nlaeval_free(&ctx->nla_channels);
nlaeval_free(&ctx->lower_eval_data);
}
BLI_freelistN(cache);

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

@ -237,7 +237,7 @@ void BKE_id_free_us(Main *bmain, void *idv) /* test users */
}
}
static void id_delete(Main *bmain, const bool do_tagged_deletion)
static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
{
const int tag = LIB_TAG_DOIT;
ListBase *lbarray[MAX_LIBARRAY];
@ -346,6 +346,7 @@ static void id_delete(Main *bmain, const bool do_tagged_deletion)
* have been already cleared when we reach it
* (e.g. Objects being processed before meshes, they'll have already released their 'reference'
* over meshes when we come to freeing obdata). */
size_t num_datablocks_deleted = 0;
for (i = do_tagged_deletion ? 1 : base_count; i--;) {
ListBase *lb = lbarray[i];
ID *id, *id_next;
@ -360,11 +361,13 @@ static void id_delete(Main *bmain, const bool do_tagged_deletion)
BLI_assert(id->us == 0);
}
BKE_id_free_ex(bmain, id, free_flag, !do_tagged_deletion);
++num_datablocks_deleted;
}
}
}
bmain->is_memfile_undo_written = false;
return num_datablocks_deleted;
}
/**
@ -386,8 +389,9 @@ void BKE_id_delete(Main *bmain, void *idv)
*
* \warning Considered experimental for now, seems to be working OK but this is
* risky code in a complicated area.
* \return Number of deleted datablocks.
*/
void BKE_id_multi_tagged_delete(Main *bmain)
size_t BKE_id_multi_tagged_delete(Main *bmain)
{
id_delete(bmain, true);
return id_delete(bmain, true);
}

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

@ -1317,9 +1317,7 @@ ModifierData *BKE_object_active_modifier(const Object *ob)
bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
{
const ModifierTypeInfo *mti;
mti = BKE_modifier_get_info(modifier_type);
const ModifierTypeInfo *mti = BKE_modifier_get_info(modifier_type);
/* Only geometry objects should be able to get modifiers T25291. */
if (ob->type == OB_HAIR) {
@ -1349,8 +1347,6 @@ bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
bool BKE_object_copy_modifier(struct Object *ob_dst, const struct Object *ob_src, ModifierData *md)
{
ModifierData *nmd = NULL;
if (ELEM(md->type, eModifierType_Hook, eModifierType_Collision)) {
return false;
}
@ -1369,7 +1365,7 @@ bool BKE_object_copy_modifier(struct Object *ob_dst, const struct Object *ob_src
break;
}
nmd = BKE_modifier_new(md->type);
ModifierData *nmd = BKE_modifier_new(md->type);
BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
if (md->type == eModifierType_Multires) {
@ -1387,9 +1383,7 @@ bool BKE_object_copy_modifier(struct Object *ob_dst, const struct Object *ob_src
bool BKE_object_copy_gpencil_modifier(struct Object *ob_dst, GpencilModifierData *md)
{
GpencilModifierData *nmd = NULL;
nmd = BKE_gpencil_modifier_new(md->type);
GpencilModifierData *nmd = BKE_gpencil_modifier_new(md->type);
BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
@ -1604,7 +1598,6 @@ void BKE_object_free_derived_caches(Object *ob)
void BKE_object_free_caches(Object *object)
{
ModifierData *md;
short update_flag = 0;
/* Free particle system caches holding paths. */
@ -1617,7 +1610,7 @@ void BKE_object_free_caches(Object *object)
}
/* Free memory used by cached derived meshes in the particle system modifiers. */
for (md = object->modifiers.first; md != NULL; md = md->next) {
LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
if (md->type == eModifierType_ParticleSystem) {
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
if (psmd->mesh_final) {
@ -1845,19 +1838,16 @@ int BKE_object_visibility(const Object *ob, const int dag_eval_mode)
bool BKE_object_exists_check(Main *bmain, const Object *obtest)
{
Object *ob;
if (obtest == NULL) {
return false;
}
ob = bmain->objects.first;
while (ob) {
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
if (ob == obtest) {
return true;
}
ob = ob->id.next;
}
return false;
}
@ -2012,14 +2002,12 @@ int BKE_object_obdata_to_type(const ID *id)
*/
Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
{
Object *ob;
if (!name) {
name = get_obdata_defname(type);
}
/* We cannot use #BKE_id_new here as we need some custom initialization code. */
ob = BKE_libblock_alloc(bmain, ID_OB, name, 0);
Object *ob = BKE_libblock_alloc(bmain, ID_OB, name, 0);
/* We increase object user count when linking to Collections. */
id_us_min(&ob->id);
@ -2032,9 +2020,7 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
static Object *object_add_common(Main *bmain, ViewLayer *view_layer, int type, const char *name)
{
Object *ob;
ob = BKE_object_add_only_object(bmain, type, name);
Object *ob = BKE_object_add_only_object(bmain, type, name);
ob->data = BKE_object_obdata_add_from_type(bmain, type, name);
BKE_view_layer_base_deselect_all(view_layer);
@ -2053,16 +2039,12 @@ static Object *object_add_common(Main *bmain, ViewLayer *view_layer, int type, c
*/
Object *BKE_object_add(Main *bmain, ViewLayer *view_layer, int type, const char *name)
{
Object *ob;
Base *base;
LayerCollection *layer_collection;
Object *ob = object_add_common(bmain, view_layer, type, name);
ob = object_add_common(bmain, view_layer, type, name);
layer_collection = BKE_layer_collection_get_active(view_layer);
LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer);
BKE_collection_object_add(bmain, layer_collection->collection, ob);
base = BKE_view_layer_base_find(view_layer, ob);
Base *base = BKE_view_layer_base_find(view_layer, ob);
BKE_view_layer_base_select_and_set_active(view_layer, base);
return ob;
@ -2076,13 +2058,10 @@ Object *BKE_object_add(Main *bmain, ViewLayer *view_layer, int type, const char
Object *BKE_object_add_from(
Main *bmain, Scene *scene, ViewLayer *view_layer, int type, const char *name, Object *ob_src)
{
Object *ob;
Base *base;
ob = object_add_common(bmain, view_layer, type, name);
Object *ob = object_add_common(bmain, view_layer, type, name);
BKE_collection_object_add_from(bmain, scene, ob_src, ob);
base = BKE_view_layer_base_find(view_layer, ob);
Base *base = BKE_view_layer_base_find(view_layer, ob);
BKE_view_layer_base_select_and_set_active(view_layer, base);
return ob;
@ -2100,12 +2079,8 @@ Object *BKE_object_add_from(
Object *BKE_object_add_for_data(
Main *bmain, ViewLayer *view_layer, int type, const char *name, ID *data, bool do_id_user)
{
Object *ob;
Base *base;
LayerCollection *layer_collection;
/* same as object_add_common, except we don't create new ob->data */
ob = BKE_object_add_only_object(bmain, type, name);
Object *ob = BKE_object_add_only_object(bmain, type, name);
ob->data = data;
if (do_id_user) {
id_us_plus(data);
@ -2115,10 +2090,10 @@ Object *BKE_object_add_for_data(
DEG_id_tag_update_ex(
bmain, &ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
layer_collection = BKE_layer_collection_get_active(view_layer);
LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer);
BKE_collection_object_add(bmain, layer_collection->collection, ob);
base = BKE_view_layer_base_find(view_layer, ob);
Base *base = BKE_view_layer_base_find(view_layer, ob);
BKE_view_layer_base_select_and_set_active(view_layer, base);
return ob;
@ -2127,7 +2102,6 @@ Object *BKE_object_add_for_data(
void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src, const int flag)
{
SoftBody *sb = ob_src->soft;
SoftBody *sbn;
bool tagged_no_main = ob_dst->id.tag & LIB_TAG_NO_MAIN;
ob_dst->softflag = ob_src->softflag;
@ -2136,7 +2110,7 @@ void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src
return;
}
sbn = MEM_dupallocN(sb);
SoftBody *sbn = MEM_dupallocN(sb);
if ((flag & LIB_ID_COPY_CACHES) == 0) {
sbn->totspring = sbn->totpoint = 0;
@ -2234,22 +2208,19 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys, const int f
void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src, const int flag)
{
ParticleSystem *psys, *npsys;
ModifierData *md;
if (ob_dst->type != OB_MESH) {
/* currently only mesh objects can have soft body */
return;
}
BLI_listbase_clear(&ob_dst->particlesystem);
for (psys = ob_src->particlesystem.first; psys; psys = psys->next) {
npsys = BKE_object_copy_particlesystem(psys, flag);
LISTBASE_FOREACH (ParticleSystem *, psys, &ob_src->particlesystem) {
ParticleSystem *npsys = BKE_object_copy_particlesystem(psys, flag);
BLI_addtail(&ob_dst->particlesystem, npsys);
/* need to update particle modifiers too */
for (md = ob_dst->modifiers.first; md; md = md->next) {
LISTBASE_FOREACH (ModifierData *, md, &ob_dst->modifiers) {
if (md->type == eModifierType_ParticleSystem) {
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
if (psmd->psys == psys) {
@ -2281,22 +2252,18 @@ void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src, const
static void copy_object_pose(Object *obn, const Object *ob, const int flag)
{
bPoseChannel *chan;
/* note: need to clear obn->pose pointer first,
* so that BKE_pose_copy_data works (otherwise there's a crash) */
obn->pose = NULL;
BKE_pose_copy_data_ex(&obn->pose, ob->pose, flag, true); /* true = copy constraints */
for (chan = obn->pose->chanbase.first; chan; chan = chan->next) {
bConstraint *con;
LISTBASE_FOREACH (bPoseChannel *, chan, &obn->pose->chanbase) {
chan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE);
/* XXX Remapping object pointing onto itself should be handled by generic
* BKE_library_remap stuff, but...
* the flush_constraint_targets callback am not sure about, so will delay that for now. */
for (con = chan->constraints.first; con; con = con->next) {
LISTBASE_FOREACH (bConstraint *, con, &chan->constraints) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@ -3159,7 +3126,6 @@ static bool ob_parcurve(Object *ob, Object *par, float r_mat[4][4])
static void ob_parbone(Object *ob, Object *par, float r_mat[4][4])
{
bPoseChannel *pchan;
float vec[3];
if (par->type != OB_ARMATURE) {
@ -3168,7 +3134,7 @@ static void ob_parbone(Object *ob, Object *par, float r_mat[4][4])
}
/* Make sure the bone is still valid */
pchan = BKE_pose_channel_find_name(par->pose, ob->parsubstr);
bPoseChannel *pchan = BKE_pose_channel_find_name(par->pose, ob->parsubstr);
if (!pchan || !pchan->bone) {
CLOG_ERROR(
&LOG, "Object %s with Bone parent: bone %s doesn't exist", ob->id.name + 2, ob->parsubstr);
@ -3312,7 +3278,6 @@ static void give_parvert(Object *par, int nr, float vec[3])
static void ob_parvert3(Object *ob, Object *par, float r_mat[4][4])
{
/* in local ob space */
if (OB_TYPE_SUPPORT_PARVERT(par->type)) {
float cmat[3][3], v1[3], v2[3], v3[3], q[4];
@ -3336,14 +3301,13 @@ void BKE_object_get_parent_matrix(Object *ob, Object *par, float r_parentmat[4][
{
float tmat[4][4];
float vec[3];
bool ok;
switch (ob->partype & PARTYPE) {
case PAROBJECT:
ok = 0;
case PAROBJECT: {
bool ok = false;
if (par->type == OB_CURVE) {
if ((((Curve *)par->data)->flag & CU_PATH) && (ob_parcurve(ob, par, tmat))) {
ok = 1;
ok = true;
}
}
@ -3355,6 +3319,7 @@ void BKE_object_get_parent_matrix(Object *ob, Object *par, float r_parentmat[4][
}
break;
}
case PARBONE:
ob_parbone(ob, par, tmat);
mul_m4_m4m4(r_parentmat, par->obmat, tmat);
@ -3611,10 +3576,9 @@ void BKE_object_apply_mat4(Object *ob,
BoundBox *BKE_boundbox_alloc_unit(void)
{
BoundBox *bb;
const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
bb = MEM_callocN(sizeof(BoundBox), "OB-BoundBox");
BoundBox *bb = MEM_callocN(sizeof(BoundBox), "OB-BoundBox");
BKE_boundbox_init_from_minmax(bb, min, max);
return bb;
@ -3745,9 +3709,7 @@ void BKE_object_boundbox_calc_from_mesh(struct Object *ob, struct Mesh *me_eval)
void BKE_object_dimensions_get(Object *ob, float r_vec[3])
{
BoundBox *bb = NULL;
bb = BKE_object_boundbox_get(ob);
BoundBox *bb = BKE_object_boundbox_get(ob);
if (bb) {
float scale[3];
@ -3776,9 +3738,7 @@ void BKE_object_dimensions_set_ex(Object *ob,
const float ob_scale_orig[3],
const float ob_obmat_orig[4][4])
{
BoundBox *bb = NULL;
bb = BKE_object_boundbox_get(ob);
BoundBox *bb = BKE_object_boundbox_get(ob);
if (bb) {
float len[3];
@ -3812,7 +3772,6 @@ void BKE_object_dimensions_set(Object *ob, const float value[3], int axis_mask)
void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool use_hidden)
{
BoundBox bb;
float vec[3];
bool changed = false;
@ -3820,19 +3779,19 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us
case OB_CURVE:
case OB_FONT:
case OB_SURF: {
bb = *BKE_curve_boundbox_get(ob);
BoundBox bb = *BKE_curve_boundbox_get(ob);
BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max);
changed = true;
break;
}
case OB_MESH: {
bb = *BKE_mesh_boundbox_get(ob);
BoundBox bb = *BKE_mesh_boundbox_get(ob);
BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max);
changed = true;
break;
}
case OB_GPENCIL: {
bb = *BKE_gpencil_boundbox_get(ob);
BoundBox bb = *BKE_gpencil_boundbox_get(ob);
BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max);
changed = true;
break;
@ -3868,20 +3827,20 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us
break;
}
case OB_HAIR: {
bb = *BKE_hair_boundbox_get(ob);
BoundBox bb = *BKE_hair_boundbox_get(ob);
BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max);
changed = true;
break;
}
case OB_POINTCLOUD: {
bb = *BKE_pointcloud_boundbox_get(ob);
BoundBox bb = *BKE_pointcloud_boundbox_get(ob);
BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max);
changed = true;
break;
}
case OB_VOLUME: {
bb = *BKE_volume_boundbox_get(ob);
BoundBox bb = *BKE_volume_boundbox_get(ob);
BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max);
changed = true;
break;
@ -3997,9 +3956,8 @@ bool BKE_object_minmax_dupli(Depsgraph *depsgraph,
return ok;
}
ListBase *lb;
DupliObject *dob;
lb = object_duplilist(depsgraph, scene, ob);
ListBase *lb = object_duplilist(depsgraph, scene, ob);
for (dob = lb->first; dob; dob = dob->next) {
if ((use_hidden == false) && (dob->no_draw != 0)) {
/* pass */
@ -4398,14 +4356,13 @@ int BKE_object_insert_ptcache(Object *ob)
static int pc_findindex(ListBase *listbase, int index)
{
LinkData *link = NULL;
int number = 0;
if (listbase == NULL) {
return -1;
}
link = listbase->first;
LinkData *link = listbase->first;
while (link) {
if (POINTER_AS_INT(link->data) == index) {
return number;
@ -4797,6 +4754,13 @@ static bool constructive_modifier_is_deform_modified(ModifierData *md)
*/
return true;
}
if (md->type == eModifierType_Nodes) {
/* Not ideal for performance to always assume this is animated,
* but hard to detect in general. The better long term solution is likely
* to replace BKE_object_is_deform_modified by a test if the object was
* modified by the depsgraph when changing frames. */
return true;
}
return false;
}

View File

@ -1597,7 +1597,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;
@ -1613,20 +1613,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,
@ -1661,12 +1654,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 {
@ -1932,6 +1920,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

@ -156,8 +156,8 @@ typedef struct NlaKeyframingContext {
NlaStrip strip;
NlaEvalStrip *eval_strip;
/* Evaluated NLA stack below the current strip. */
NlaEvalData nla_channels;
/* Evaluated NLA stack below the tweak strip. */
NlaEvalData lower_eval_data;
} NlaKeyframingContext;
/* --------------- NLA Functions (not to be used as a proper API) ----------------------- */

View File

@ -113,7 +113,9 @@ static void seq_convert_transform_animation(const Scene *scene,
BezTriple *bezt = fcu->bezt;
for (int i = 0; i < fcu->totvert; i++, bezt++) {
/* Same math as with old_image_center_*, but simplified. */
bezt->vec[0][1] = image_size / 2 + bezt->vec[0][1] - scene->r.xsch / 2;
bezt->vec[1][1] = image_size / 2 + bezt->vec[1][1] - scene->r.xsch / 2;
bezt->vec[2][1] = image_size / 2 + bezt->vec[2][1] - scene->r.xsch / 2;
}
}
}
@ -250,7 +252,9 @@ static void seq_convert_transform_animation_2(const Scene *scene,
BezTriple *bezt = fcu->bezt;
for (int i = 0; i < fcu->totvert; i++, bezt++) {
/* Same math as with old_image_center_*, but simplified. */
bezt->vec[0][1] *= scale_to_fit_factor;
bezt->vec[1][1] *= scale_to_fit_factor;
bezt->vec[2][1] *= scale_to_fit_factor;
}
}
}
@ -286,6 +290,12 @@ static void seq_convert_transform_crop_2(const Scene *scene,
char name_esc[(sizeof(seq->name) - 2) * 2], *path;
BLI_str_escape(name_esc, seq->name + 2, sizeof(name_esc));
path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].transform.scale_x", name_esc);
seq_convert_transform_animation_2(scene, path, scale_to_fit_factor);
MEM_freeN(path);
path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].transform.scale_y", name_esc);
seq_convert_transform_animation_2(scene, path, scale_to_fit_factor);
MEM_freeN(path);
path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].crop.min_x", name_esc);
seq_convert_transform_animation_2(scene, path, 1 / scale_to_fit_factor);
MEM_freeN(path);
@ -1430,18 +1440,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) {
@ -1462,5 +1461,44 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
FOREACH_NODETREE_END;
/* Default properties editors to auto outliner sync. */
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) {
if (space->spacetype == SPACE_PROPERTIES) {
SpaceProperties *space_properties = (SpaceProperties *)space;
space_properties->outliner_sync = PROPERTIES_SYNC_AUTO;
}
}
}
}
/* 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

@ -397,7 +397,7 @@ static void drw_mesh_weight_state_extract(Object *ob,
wstate->flags |= DRW_MESH_WEIGHT_STATE_MULTIPAINT |
(ts->auto_normalize ? DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE : 0);
if (me->symmetry & ME_SYMMETRY_X) {
if (me->editflag & ME_EDIT_VERTEX_GROUPS_X_SYMMETRY) {
BKE_object_defgroup_mirror_selection(ob,
wstate->defgroup_len,
wstate->defgroup_sel,

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

@ -3422,7 +3422,7 @@ static void ANIM_OT_channels_click(wmOperatorType *ot)
/* identifiers */
ot->name = "Mouse Click on Channels";
ot->idname = "ANIM_OT_channels_click";
ot->description = "Handle mouse-clicks over animation channels";
ot->description = "Handle mouse clicks over animation channels";
/* api callbacks */
ot->invoke = animchannels_mouseclick_invoke;

View File

@ -1617,7 +1617,7 @@ void ARMATURE_OT_bone_primitive_add(wmOperatorType *ot)
/* identifiers */
ot->name = "Add Bone";
ot->idname = "ARMATURE_OT_bone_primitive_add";
ot->description = "Add a new bone located at the 3D-Cursor";
ot->description = "Add a new bone located at the 3D cursor";
/* api callbacks */
ot->exec = armature_bone_primitive_add_exec;

View File

@ -876,7 +876,7 @@ void ARMATURE_OT_fill(wmOperatorType *ot)
/* identifiers */
ot->name = "Fill Between Joints";
ot->idname = "ARMATURE_OT_fill";
ot->description = "Add bone between selected joint(s) and/or 3D-Cursor";
ot->description = "Add bone between selected joint(s) and/or 3D cursor";
/* callbacks */
ot->exec = armature_fill_bones_exec;

View File

@ -948,7 +948,7 @@ void ARMATURE_OT_parent_set(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_enum(
ot->srna, "type", prop_editarm_make_parent_types, 0, "ParentType", "Type of parenting");
ot->srna, "type", prop_editarm_make_parent_types, 0, "Parent Type", "Type of parenting");
}
static const EnumPropertyItem prop_editarm_clear_parent_types[] = {
@ -1029,7 +1029,7 @@ void ARMATURE_OT_parent_clear(wmOperatorType *ot)
"type",
prop_editarm_clear_parent_types,
0,
"ClearType",
"Clear Type",
"What way to clear parenting");
}

View File

@ -1802,7 +1802,7 @@ static int textbox_add_exec(bContext *C, wmOperator *UNUSED(op))
void FONT_OT_textbox_add(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Add Textbox";
ot->name = "Add Text Box";
ot->description = "Add a new text box";
ot->idname = "FONT_OT_textbox_add";
@ -1846,8 +1846,8 @@ static int textbox_remove_exec(bContext *C, wmOperator *op)
void FONT_OT_textbox_remove(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Remove Textbox";
ot->description = "Remove the textbox";
ot->name = "Remove Text Box";
ot->description = "Remove the text box";
ot->idname = "FONT_OT_textbox_remove";
/* api callbacks */

View File

@ -1906,7 +1906,7 @@ void GPENCIL_OT_brush_reset(wmOperatorType *ot)
/* identifiers */
ot->name = "Reset Brush";
ot->idname = "GPENCIL_OT_brush_reset";
ot->description = "Reset Brush to default parameters";
ot->description = "Reset brush to default parameters";
/* api callbacks */
ot->exec = gpencil_brush_reset_exec;

View File

@ -341,7 +341,7 @@ void GPENCIL_OT_selectmode_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
/* properties */
prop = RNA_def_int(ot->srna, "mode", 0, 0, 2, "Select mode", "Select mode", 0, 2);
prop = RNA_def_int(ot->srna, "mode", 0, 0, 2, "Select Mode", "Select mode", 0, 2);
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
@ -2759,7 +2759,7 @@ void GPENCIL_OT_dissolve(wmOperatorType *ot)
prop_gpencil_dissolve_types,
0,
"Type",
"Method used for dissolving Stroke points");
"Method used for dissolving stroke points");
}
/** \} */
@ -3442,7 +3442,7 @@ void GPENCIL_OT_stroke_caps_set(wmOperatorType *ot)
/* identifiers */
ot->name = "Set Caps Mode";
ot->idname = "GPENCIL_OT_stroke_caps_set";
ot->description = "Change Stroke caps mode (rounded or flat)";
ot->description = "Change stroke caps mode (rounded or flat)";
/* api callbacks */
ot->exec = gpencil_stroke_caps_set_exec;

View File

@ -1707,6 +1707,6 @@ void GPENCIL_OT_fill(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
prop = RNA_def_boolean(ot->srna, "on_back", false, "Draw On Back", "Send new stroke to Back");
prop = RNA_def_boolean(ot->srna, "on_back", false, "Draw on Back", "Send new stroke to back");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}

View File

@ -434,7 +434,7 @@ void GPENCIL_OT_bake_mesh_animation(wmOperatorType *ot)
/* identifiers */
ot->name = "Bake Mesh Animation to Grease Pencil";
ot->idname = "GPENCIL_OT_bake_mesh_animation";
ot->description = "Bake Mesh Animation to Grease Pencil strokes";
ot->description = "Bake mesh animation to grease pencil strokes";
/* callbacks */
ot->invoke = gpencil_bake_mesh_animation_invoke;

View File

@ -452,7 +452,7 @@ void GPENCIL_OT_transform_fill(wmOperatorType *ot)
/* identifiers */
ot->name = "Transform Stroke Fill";
ot->idname = "GPENCIL_OT_transform_fill";
ot->description = "Transform Grease Pencil Stroke Fill";
ot->description = "Transform grease pencil stroke fill";
/* api callbacks */
ot->invoke = gpencil_transform_fill_invoke;

View File

@ -26,6 +26,7 @@
extern "C" {
#endif
struct ScrArea;
struct SpaceProperties;
struct bContext;
@ -36,7 +37,13 @@ void ED_buttons_search_string_set(struct SpaceProperties *sbuts, const char *val
int ED_buttons_search_string_length(struct SpaceProperties *sbuts);
const char *ED_buttons_search_string_get(struct SpaceProperties *sbuts);
void ED_buttons_set_context(const struct bContext *C, PointerRNA *ptr, const int context);
bool ED_buttons_should_sync_with_outliner(const struct bContext *C,
const struct SpaceProperties *sbuts,
struct ScrArea *area);
void ED_buttons_set_context(const struct bContext *C,
struct SpaceProperties *sbuts,
PointerRNA *ptr,
const int context);
#ifdef __cplusplus
}

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

@ -349,7 +349,7 @@ static bool eyedropper_colorband_poll(bContext *C)
void UI_OT_eyedropper_colorramp(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Eyedropper colorband";
ot->name = "Eyedropper Colorband";
ot->idname = "UI_OT_eyedropper_colorramp";
ot->description = "Sample a color band";
@ -369,7 +369,7 @@ void UI_OT_eyedropper_colorramp(wmOperatorType *ot)
void UI_OT_eyedropper_colorramp_point(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Eyedropper colorband (points)";
ot->name = "Eyedropper Colorband (Points)";
ot->idname = "UI_OT_eyedropper_colorramp_point";
ot->description = "Point-sample a color band";

View File

@ -2200,7 +2200,7 @@ int UI_icon_from_library(const ID *id)
return ICON_LIBRARY_DATA_OVERRIDE;
}
if (ID_IS_ASSET(id)) {
return ICON_MAT_SPHERE_SKY;
return ICON_ASSET_MANAGER;
}
return ICON_NONE;

View File

@ -1380,6 +1380,11 @@ static void template_id_name_button(
but, template_ui->duplicate_op, WM_OP_INVOKE_DEFAULT, ICON_DUPLICATE);
}
if (template_ui->open_op && (flag & UI_ID_OPEN)) {
UI_but_extra_operator_icon_add(
but, template_ui->open_op, WM_OP_INVOKE_DEFAULT, ICON_FILEBROWSER);
}
if (id && (flag & UI_ID_DELETE)) {
const bool never_unlink = RNA_property_flag(template_ui->prop) &
(PROP_NEVER_UNLINK | PROP_NEVER_NULL);
@ -1387,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);
}
}
@ -1396,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

@ -4771,73 +4771,75 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
}
}
if (wt) {
// rcti disablerect = *rect; /* rect gets clipped smaller for text */
if (wt == NULL) {
return;
}
const int roundboxalign = widget_roundbox_set(but, rect);
// rcti disablerect = *rect; /* rect gets clipped smaller for text */
/* Mask out flags re-used for local state. */
int state = but->flag & ~UI_STATE_FLAGS_ALL;
const int drawflag = but->drawflag;
const int roundboxalign = widget_roundbox_set(but, rect);
if (state & UI_SELECT_DRAW) {
state |= UI_SELECT;
/* Mask out flags re-used for local state. */
int state = but->flag & ~UI_STATE_FLAGS_ALL;
const int drawflag = but->drawflag;
if (state & UI_SELECT_DRAW) {
state |= UI_SELECT;
}
if ((but->editstr) ||
(UNLIKELY(but->flag & UI_BUT_DRAG_MULTI) && ui_but_drag_multi_edit_get(but))) {
state |= UI_STATE_TEXT_INPUT;
}
if (but->hold_func) {
state |= UI_STATE_HOLD_ACTION;
}
if (state & UI_ACTIVE) {
if (but->drawflag & UI_BUT_ACTIVE_LEFT) {
state |= UI_STATE_ACTIVE_LEFT;
}
if ((but->editstr) ||
(UNLIKELY(but->flag & UI_BUT_DRAG_MULTI) && ui_but_drag_multi_edit_get(but))) {
state |= UI_STATE_TEXT_INPUT;
else if (but->drawflag & UI_BUT_ACTIVE_RIGHT) {
state |= UI_STATE_ACTIVE_RIGHT;
}
}
if (but->hold_func) {
state |= UI_STATE_HOLD_ACTION;
bool use_alpha_blend = false;
if (but->emboss != UI_EMBOSS_PULLDOWN) {
if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_SEARCH_FILTER_NO_MATCH)) {
use_alpha_blend = true;
ui_widget_color_disabled(wt, state);
}
}
if (state & UI_ACTIVE) {
if (but->drawflag & UI_BUT_ACTIVE_LEFT) {
state |= UI_STATE_ACTIVE_LEFT;
}
else if (but->drawflag & UI_BUT_ACTIVE_RIGHT) {
state |= UI_STATE_ACTIVE_RIGHT;
}
}
bool use_alpha_blend = false;
if (but->emboss != UI_EMBOSS_PULLDOWN) {
if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_SEARCH_FILTER_NO_MATCH)) {
use_alpha_blend = true;
ui_widget_color_disabled(wt, state);
}
}
if (drawflag & UI_BUT_TEXT_RIGHT) {
state |= UI_STATE_TEXT_BEFORE_WIDGET;
}
if (drawflag & UI_BUT_TEXT_RIGHT) {
state |= UI_STATE_TEXT_BEFORE_WIDGET;
}
#ifdef USE_UI_POPOVER_ONCE
if (but->block->flag & UI_BLOCK_POPOVER_ONCE) {
if ((state & UI_ACTIVE) && ui_but_is_popover_once_compat(but)) {
state |= UI_BUT_ACTIVE_DEFAULT;
}
if (but->block->flag & UI_BLOCK_POPOVER_ONCE) {
if ((state & UI_ACTIVE) && ui_but_is_popover_once_compat(but)) {
state |= UI_BUT_ACTIVE_DEFAULT;
}
}
#endif
wt->state(wt, state, drawflag, but->emboss);
if (wt->custom) {
wt->custom(but, &wt->wcol, rect, state, roundboxalign);
}
else if (wt->draw) {
wt->draw(&wt->wcol, rect, state, roundboxalign);
}
wt->state(wt, state, drawflag, but->emboss);
if (wt->custom) {
wt->custom(but, &wt->wcol, rect, state, roundboxalign);
}
else if (wt->draw) {
wt->draw(&wt->wcol, rect, state, roundboxalign);
}
if (use_alpha_blend) {
GPU_blend(GPU_BLEND_ALPHA);
}
if (use_alpha_blend) {
GPU_blend(GPU_BLEND_ALPHA);
}
wt->text(fstyle, &wt->wcol, but, rect);
if (use_alpha_blend) {
GPU_blend(GPU_BLEND_NONE);
}
wt->text(fstyle, &wt->wcol, but, rect);
if (use_alpha_blend) {
GPU_blend(GPU_BLEND_NONE);
}
}

View File

@ -428,7 +428,7 @@ void WM_OT_alembic_export(wmOperatorType *ot)
"triangulate",
false,
"Triangulate",
"Export Polygons (Quads & NGons) as Triangles");
"Export polygons (quads and n-gons) as triangles");
RNA_def_enum(ot->srna,
"quad_method",

View File

@ -481,11 +481,11 @@ void WM_OT_collada_export(wmOperatorType *ot)
{0, NULL, 0, NULL, NULL}};
static const EnumPropertyItem prop_bc_export_ui_section[] = {
{BC_UI_SECTION_MAIN, "main", 0, "Main", "Data Export Section"},
{BC_UI_SECTION_GEOMETRY, "geometry", 0, "Geom", "Geometry Export Section"},
{BC_UI_SECTION_ARMATURE, "armature", 0, "Arm", "Armature Export Section"},
{BC_UI_SECTION_ANIMATION, "animation", 0, "Anim", "Animation Export Section"},
{BC_UI_SECTION_COLLADA, "collada", 0, "Extra", "Collada Export Section"},
{BC_UI_SECTION_MAIN, "main", 0, "Main", "Data export section"},
{BC_UI_SECTION_GEOMETRY, "geometry", 0, "Geom", "Geometry export section"},
{BC_UI_SECTION_ARMATURE, "armature", 0, "Arm", "Armature export section"},
{BC_UI_SECTION_ANIMATION, "animation", 0, "Anim", "Animation export section"},
{BC_UI_SECTION_COLLADA, "collada", 0, "Extra", "Collada export section"},
{0, NULL, 0, NULL, NULL}};
ot->name = "Export COLLADA";
@ -649,7 +649,7 @@ void WM_OT_collada_export(wmOperatorType *ot)
"Copy textures to same folder where the .dae file is exported");
RNA_def_boolean(
func, "triangulate", 1, "Triangulate", "Export Polygons (Quads & NGons) as Triangles");
func, "triangulate", 1, "Triangulate", "Export polygons (quads and n-gons) as triangles");
RNA_def_boolean(func,
"use_object_instantiation",

View File

@ -239,7 +239,7 @@ void MESH_OT_primitive_cube_add(wmOperatorType *ot)
static const EnumPropertyItem fill_type_items[] = {
{0, "NOTHING", 0, "Nothing", "Don't fill at all"},
{1, "NGON", 0, "Ngon", "Use ngons"},
{1, "NGON", 0, "N-Gon", "Use n-gons"},
{2, "TRIFAN", 0, "Triangle Fan", "Use triangle fans"},
{0, NULL, 0, NULL, NULL},
};

View File

@ -1055,7 +1055,7 @@ void MESH_OT_bevel(wmOperatorType *ot)
"CUTOFF",
0,
"Cutoff",
"A cut-off at each profile's end before the intersection"},
"A cutoff at each profile's end before the intersection"},
{0, NULL, 0, NULL, NULL},
};

View File

@ -612,7 +612,7 @@ void MESH_OT_inset(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "use_outset", false, "Outset", "Outset rather than inset");
RNA_def_boolean(
ot->srna, "use_select_inset", false, "Select Outer", "Select the new inset faces");
RNA_def_boolean(ot->srna, "use_individual", false, "Individual", "Individual Face Inset");
RNA_def_boolean(ot->srna, "use_individual", false, "Individual", "Individual face inset");
RNA_def_boolean(
ot->srna, "use_interpolate", true, "Interpolate", "Blend face data across the inset");

Some files were not shown because too many files have changed in this diff Show More