Merge branch 'master' into temp_bmesh_multires
This commit is contained in:
commit
35092510ba
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
|
||||
|
||||
#define MANTA_GIT_VERSION "commit 327917cd59b03bef3a953b5f58fc1637b3a83e01"
|
||||
#define MANTA_GIT_VERSION "commit e2285cb9bc492987f728123be6cfc1fe11fe73d6"
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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\
|
||||
|
|
|
@ -558,6 +558,7 @@ def dump_py_messages_from_files(msgs, reports, files, settings):
|
|||
"msgid": ((("msgctxt",), _ctxt_to_ctxt),
|
||||
),
|
||||
"message": (),
|
||||
"heading": (),
|
||||
}
|
||||
|
||||
context_kw_set = {}
|
||||
|
|
|
@ -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"),
|
||||
]
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ class SpellChecker:
|
|||
"boolean", "booleans",
|
||||
"chamfer",
|
||||
"couldn", # couldn't
|
||||
"customizable",
|
||||
"decrement",
|
||||
"derivate",
|
||||
"deterministically",
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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'}
|
||||
|
|
|
@ -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'}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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..."
|
||||
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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=(),
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -514,6 +514,7 @@ geometry_node_categories = [
|
|||
NodeItem("GeometryNodePointDistribute"),
|
||||
NodeItem("GeometryNodePointInstance"),
|
||||
NodeItem("GeometryNodePointSeparate"),
|
||||
NodeItem("GeometryNodeRotatePoints"),
|
||||
]),
|
||||
GeometryNodeCategory("GEO_UTILITIES", "Utilities", items=[
|
||||
NodeItem("ShaderNodeMapRange"),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) ----------------------- */
|
||||
|
|
|
@ -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. */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 ************* */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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";
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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},
|
||||
};
|
||||
|
|
|
@ -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},
|
||||
};
|
||||
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue