Merge remote-tracking branch 'origin/master' into sculpt-dev

This commit is contained in:
Joseph Eagar 2022-04-14 22:25:34 -07:00
commit ecbf681e31
463 changed files with 11747 additions and 7048 deletions

View File

@ -446,7 +446,7 @@ if(NOT APPLE)
endif()
option(WITH_CYCLES_HIP_BINARIES "Build Cycles AMD HIP binaries" OFF)
set(CYCLES_HIP_BINARIES_ARCH gfx900 gfx906 gfx1010 gfx1011 gfx1012 gfx1030 gfx1031 gfx1032 gfx1034 CACHE STRING "AMD HIP architectures to build binaries for")
set(CYCLES_HIP_BINARIES_ARCH gfx1010 gfx1011 gfx1012 gfx1030 gfx1031 gfx1032 gfx1034 CACHE STRING "AMD HIP architectures to build binaries for")
mark_as_advanced(WITH_CYCLES_DEVICE_HIP)
mark_as_advanced(CYCLES_HIP_BINARIES_ARCH)
endif()

View File

@ -4004,6 +4004,7 @@ install_DEB() {
WEBP_DEV="libwebp-dev"
check_package_DEB $WEBP_DEV
if [ $? -eq 0 ]; then
install_packages_DEB $WEBP_DEV
WEBP_USE=true
fi
@ -4435,9 +4436,6 @@ install_DEB() {
if [ "$VPX_USE" = true ]; then
_packages="$_packages $VPX_DEV"
fi
if [ "$WEBP_USE" = true ]; then
_packages="$_packages $WEBP_DEV"
fi
if [ "$OPUS_USE" = true ]; then
_packages="$_packages $OPUS_DEV"
fi
@ -4722,6 +4720,7 @@ install_RPM() {
WEBP_DEV="libwebp-devel"
check_package_RPM $WEBP_DEV
if [ $? -eq 0 ]; then
install_packages_RPM $WEBP_DEV
WEBP_USE=true
fi
@ -5124,9 +5123,6 @@ install_RPM() {
if [ "$VPX_USE" = true ]; then
_packages="$_packages $VPX_DEV"
fi
if [ "$WEBP_USE" = true ]; then
_packages="$_packages $WEBP_DEV"
fi
if [ "$OPUS_USE" = true ]; then
_packages="$_packages $OPUS_DEV"
fi
@ -5300,6 +5296,7 @@ install_ARCH() {
WEBP_DEV="libwebp"
check_package_ARCH $WEBP_DEV
if [ $? -eq 0 ]; then
install_packages_ARCH $WEBP_DEV
WEBP_USE=true
fi
@ -5704,16 +5701,12 @@ install_ARCH() {
if [ "$VPX_USE" = true ]; then
_packages="$_packages $VPX_DEV"
fi
if [ "$WEBP_USE" = true ]; then
_packages="$_packages $WEBP_DEV"
fi
if [ "$OPUS_USE" = true ]; then
_packages="$_packages $OPUS_DEV"
fi
if [ "$MP3LAME_USE" = true ]; then
_packages="$_packages $MP3LAME_DEV"
fi
install_packages_ARCH $_packages
compile_FFmpeg
fi
@ -5961,6 +5954,12 @@ print_info() {
fi
fi
if [ "$WEBP_USE" = true ]; then
_1="-D WITH_IMAGE_WEBP=ON"
PRINT " $_1"
_buildargs="$_buildargs $_1"
fi
if [ -d $INST/openexr ]; then
_1="-D OPENEXR_ROOT_DIR=$INST/openexr"
PRINT " $_1"

View File

@ -226,7 +226,7 @@ def list_render_passes(scene, srl):
if aov.type == 'VALUE':
yield (aov.name, "X", 'VALUE')
else:
yield (aov.name, "RGB", 'COLOR')
yield (aov.name, "RGBA", 'COLOR')
# Light groups.
for lightgroup in srl.lightgroups:

View File

@ -1507,7 +1507,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
col.label(text="and NVIDIA driver version 470 or newer", icon='BLANK1')
elif device_type == 'HIP':
import sys
col.label(text="Requires discrete AMD GPU with Vega architecture", icon='BLANK1')
col.label(text="Requires discrete AMD GPU with RDNA architecture", icon='BLANK1')
if sys.platform[:3] == "win":
col.label(text="and AMD Radeon Pro 21.Q4 driver or newer", icon='BLANK1')
elif device_type == 'METAL':

View File

@ -1916,13 +1916,20 @@ class CYCLES_RENDER_PT_bake_output_margin(CyclesButtonsPanel, Panel):
cbk = scene.render.bake
rd = scene.render
if rd.use_bake_multires:
layout.prop(rd, "bake_margin_type", text="Type")
layout.prop(rd, "bake_margin", text="Size")
if (cscene.bake_type == 'NORMAL' and cbk.normal_space == 'TANGENT') or cscene.bake_type == 'UV':
if rd.use_bake_multires:
layout.prop(rd, "bake_margin", text="Size")
else:
if cbk.target == 'IMAGE_TEXTURES':
layout.prop(cbk, "margin", text="Size")
else:
if cbk.target == 'IMAGE_TEXTURES':
layout.prop(cbk, "margin_type", text="Type")
layout.prop(cbk, "margin", text="Size")
if rd.use_bake_multires:
layout.prop(rd, "bake_margin_type", text="Type")
layout.prop(rd, "bake_margin", text="Size")
else:
if cbk.target == 'IMAGE_TEXTURES':
layout.prop(cbk, "margin_type", text="Type")
layout.prop(cbk, "margin", text="Size")

View File

@ -51,7 +51,7 @@ static inline bool hipSupportsDevice(const int hipDevId)
hipDeviceGetAttribute(&major, hipDeviceAttributeComputeCapabilityMajor, hipDevId);
hipDeviceGetAttribute(&minor, hipDeviceAttributeComputeCapabilityMinor, hipDevId);
return (major >= 9);
return (major > 10) || (major == 10 && minor >= 1);
}
CCL_NAMESPACE_END

View File

@ -3,6 +3,7 @@
* Copyright 2022 Blender Foundation */
#include "hydra/camera.h"
#include "hydra/session.h"
#include "scene/camera.h"
#include <pxr/base/gf/frustum.h>
@ -12,6 +13,19 @@
HDCYCLES_NAMESPACE_OPEN_SCOPE
extern Transform convert_transform(const GfMatrix4d &matrix);
Transform convert_camera_transform(const GfMatrix4d &matrix, float metersPerUnit)
{
Transform t = convert_transform(matrix);
// Flip Z axis
t.x.z *= -1.0f;
t.y.z *= -1.0f;
t.z.z *= -1.0f;
// Scale translation
t.x.w *= metersPerUnit;
t.y.w *= metersPerUnit;
t.z.w *= metersPerUnit;
return t;
}
#if PXR_VERSION < 2102
// clang-format off
@ -61,13 +75,20 @@ void HdCyclesCamera::Sync(HdSceneDelegate *sceneDelegate,
if (*dirtyBits & DirtyBits::DirtyTransform) {
sceneDelegate->SampleTransform(id, &_transformSamples);
bool transform_found = false;
for (size_t i = 0; i < _transformSamples.count; ++i) {
if (_transformSamples.times[i] == 0.0f) {
_transform = _transformSamples.values[i];
_data.SetTransform(_transform);
transform_found = true;
break;
}
}
if (!transform_found && _transformSamples.count) {
_transform = _transformSamples.values[0];
_data.SetTransform(_transform);
}
}
#else
if (*dirtyBits & DirtyBits::DirtyViewMatrix) {
@ -236,18 +257,21 @@ void HdCyclesCamera::Finalize(HdRenderParam *renderParam)
HdCamera::Finalize(renderParam);
}
void HdCyclesCamera::ApplyCameraSettings(Camera *cam) const
void HdCyclesCamera::ApplyCameraSettings(HdRenderParam *renderParam, Camera *cam) const
{
ApplyCameraSettings(_data, _windowPolicy, cam);
ApplyCameraSettings(renderParam, _data, _windowPolicy, cam);
const float metersPerUnit = static_cast<HdCyclesSession *>(renderParam)->GetStageMetersPerUnit();
array<Transform> motion(_transformSamples.count);
for (size_t i = 0; i < _transformSamples.count; ++i)
motion[i] = convert_transform(_transformSamples.values[i]) *
transform_scale(1.0f, 1.0f, -1.0f);
for (size_t i = 0; i < _transformSamples.count; ++i) {
motion[i] = convert_camera_transform(_transformSamples.values[i], metersPerUnit);
}
cam->set_motion(motion);
}
void HdCyclesCamera::ApplyCameraSettings(const GfCamera &dataUnconformedWindow,
void HdCyclesCamera::ApplyCameraSettings(HdRenderParam *renderParam,
const GfCamera &dataUnconformedWindow,
CameraUtilConformWindowPolicy windowPolicy,
Camera *cam)
{
@ -261,20 +285,22 @@ void HdCyclesCamera::ApplyCameraSettings(const GfCamera &dataUnconformedWindow,
GfCamera::Orthographic == CAMERA_ORTHOGRAPHIC);
cam->set_camera_type(static_cast<CameraType>(data.GetProjection()));
const float metersPerUnit = static_cast<HdCyclesSession *>(renderParam)->GetStageMetersPerUnit();
auto viewplane = data.GetFrustum().GetWindow();
auto focalLength = 1.0f;
if (data.GetProjection() == GfCamera::Perspective) {
viewplane *= 2.0 / viewplane.GetSize()[1]; // Normalize viewplane
focalLength = data.GetFocalLength() * 1e-3f;
focalLength = data.GetFocalLength() * GfCamera::FOCAL_LENGTH_UNIT * metersPerUnit;
cam->set_fov(GfDegreesToRadians(data.GetFieldOfView(GfCamera::FOVVertical)));
}
cam->set_sensorwidth(data.GetHorizontalAperture() * GfCamera::APERTURE_UNIT);
cam->set_sensorheight(data.GetVerticalAperture() * GfCamera::APERTURE_UNIT);
cam->set_sensorwidth(data.GetHorizontalAperture() * GfCamera::APERTURE_UNIT * metersPerUnit);
cam->set_sensorheight(data.GetVerticalAperture() * GfCamera::APERTURE_UNIT * metersPerUnit);
cam->set_nearclip(data.GetClippingRange().GetMin());
cam->set_farclip(data.GetClippingRange().GetMax());
cam->set_nearclip(data.GetClippingRange().GetMin() * metersPerUnit);
cam->set_farclip(data.GetClippingRange().GetMax() * metersPerUnit);
cam->set_viewplane_left(viewplane.GetMin()[0]);
cam->set_viewplane_right(viewplane.GetMax()[0]);
@ -282,14 +308,15 @@ void HdCyclesCamera::ApplyCameraSettings(const GfCamera &dataUnconformedWindow,
cam->set_viewplane_top(viewplane.GetMax()[1]);
if (data.GetFStop() != 0.0f) {
cam->set_focaldistance(data.GetFocusDistance());
cam->set_focaldistance(data.GetFocusDistance() * metersPerUnit);
cam->set_aperturesize(focalLength / (2.0f * data.GetFStop()));
}
cam->set_matrix(convert_transform(data.GetTransform()) * transform_scale(1.0f, 1.0f, -1.0f));
cam->set_matrix(convert_camera_transform(data.GetTransform(), metersPerUnit));
}
void HdCyclesCamera::ApplyCameraSettings(const GfMatrix4d &worldToViewMatrix,
void HdCyclesCamera::ApplyCameraSettings(HdRenderParam *renderParam,
const GfMatrix4d &worldToViewMatrix,
const GfMatrix4d &projectionMatrix,
const std::vector<GfVec4d> &clipPlanes,
Camera *cam)
@ -298,7 +325,7 @@ void HdCyclesCamera::ApplyCameraSettings(const GfMatrix4d &worldToViewMatrix,
GfCamera data;
data.SetFromViewAndProjectionMatrix(worldToViewMatrix, projectionMatrix);
ApplyCameraSettings(data, CameraUtilFit, cam);
ApplyCameraSettings(renderParam, data, CameraUtilFit, cam);
#else
TF_CODING_ERROR("Not implemented");
#endif

View File

@ -17,12 +17,14 @@ class HdCyclesCamera final : public PXR_NS::HdCamera {
HdCyclesCamera(const PXR_NS::SdfPath &sprimId);
~HdCyclesCamera() override;
void ApplyCameraSettings(CCL_NS::Camera *targetCamera) const;
void ApplyCameraSettings(PXR_NS::HdRenderParam *renderParam, CCL_NS::Camera *targetCamera) const;
static void ApplyCameraSettings(const PXR_NS::GfCamera &cameraData,
static void ApplyCameraSettings(PXR_NS::HdRenderParam *renderParam,
const PXR_NS::GfCamera &cameraData,
PXR_NS::CameraUtilConformWindowPolicy windowPolicy,
CCL_NS::Camera *targetCamera);
static void ApplyCameraSettings(const PXR_NS::GfMatrix4d &worldToViewMatrix,
static void ApplyCameraSettings(PXR_NS::HdRenderParam *renderParam,
const PXR_NS::GfMatrix4d &worldToViewMatrix,
const PXR_NS::GfMatrix4d &projectionMatrix,
const std::vector<PXR_NS::GfVec4d> &clipPlanes,
CCL_NS::Camera *targetCamera);

View File

@ -153,7 +153,11 @@ void HdCyclesGeometry<Base, CyclesBase>::Sync(HdSceneDelegate *sceneDelegate,
// Update transforms of all instances
for (size_t i = 0; i < transforms.size(); ++i) {
const Transform tfm = convert_transform(_geomTransform * transforms[i]);
const float metersPerUnit =
static_cast<HdCyclesSession *>(renderParam)->GetStageMetersPerUnit();
const Transform tfm = transform_scale(make_float3(metersPerUnit)) *
convert_transform(_geomTransform * transforms[i]);
_instances[i]->set_tfm(tfm);
}
}

View File

@ -54,11 +54,16 @@ void HdCyclesLight::Sync(HdSceneDelegate *sceneDelegate,
const SdfPath &id = GetId();
if (*dirtyBits & DirtyBits::DirtyTransform) {
const float metersPerUnit =
static_cast<HdCyclesSession *>(renderParam)->GetStageMetersPerUnit();
const Transform tfm = transform_scale(make_float3(metersPerUnit)) *
#if PXR_VERSION >= 2011
const Transform tfm = convert_transform(sceneDelegate->GetTransform(id));
convert_transform(sceneDelegate->GetTransform(id));
#else
const Transform tfm = convert_transform(
sceneDelegate->GetLightParamValue(id, HdTokens->transform).Get<GfMatrix4d>());
convert_transform(
sceneDelegate->GetLightParamValue(id, HdTokens->transform)
.Get<GfMatrix4d>());
#endif
_light->set_tfm(tfm);

View File

@ -33,11 +33,12 @@ TF_DEFINE_PRIVATE_TOKENS(_tokens,
);
TF_DEFINE_PRIVATE_TOKENS(HdCyclesRenderSettingsTokens,
(stageMetersPerUnit)
((device, "cycles:device"))
((threads, "cycles:threads"))
((time_limit, "cycles:time_limit"))
((timeLimit, "cycles:time_limit"))
((samples, "cycles:samples"))
((sample_offset, "cycles:sample_offset"))
((sampleOffset, "cycles:sample_offset"))
);
// clang-format on
@ -424,7 +425,7 @@ HdRenderSettingDescriptorList HdCyclesDelegate::GetRenderSettingDescriptors() co
descriptors.push_back({
"Time Limit",
HdCyclesRenderSettingsTokens->time_limit,
HdCyclesRenderSettingsTokens->timeLimit,
VtValue(0.0),
});
descriptors.push_back({
@ -434,7 +435,7 @@ HdRenderSettingDescriptorList HdCyclesDelegate::GetRenderSettingDescriptors() co
});
descriptors.push_back({
"Sample Offset",
HdCyclesRenderSettingsTokens->sample_offset,
HdCyclesRenderSettingsTokens->sampleOffset,
VtValue(0),
});
@ -452,7 +453,11 @@ void HdCyclesDelegate::SetRenderSetting(const PXR_NS::TfToken &key, const PXR_NS
Scene *const scene = _renderParam->session->scene;
Session *const session = _renderParam->session;
if (key == HdCyclesRenderSettingsTokens->time_limit) {
if (key == HdCyclesRenderSettingsTokens->stageMetersPerUnit) {
_renderParam->SetStageMetersPerUnit(
VtValue::Cast<double>(value).GetWithDefault(_renderParam->GetStageMetersPerUnit()));
}
else if (key == HdCyclesRenderSettingsTokens->timeLimit) {
session->set_time_limit(
VtValue::Cast<double>(value).GetWithDefault(session->params.time_limit));
}
@ -462,7 +467,7 @@ void HdCyclesDelegate::SetRenderSetting(const PXR_NS::TfToken &key, const PXR_NS
samples = std::min(std::max(1, samples), max_samples);
session->set_samples(samples);
}
else if (key == HdCyclesRenderSettingsTokens->sample_offset) {
else if (key == HdCyclesRenderSettingsTokens->sampleOffset) {
session->params.sample_offset = VtValue::Cast<int>(value).GetWithDefault(
session->params.sample_offset);
++_settingsVersion;
@ -484,19 +489,22 @@ VtValue HdCyclesDelegate::GetRenderSetting(const TfToken &key) const
Scene *const scene = _renderParam->session->scene;
Session *const session = _renderParam->session;
if (key == HdCyclesRenderSettingsTokens->device) {
if (key == HdCyclesRenderSettingsTokens->stageMetersPerUnit) {
return VtValue(_renderParam->GetStageMetersPerUnit());
}
else if (key == HdCyclesRenderSettingsTokens->device) {
return VtValue(TfToken(Device::string_from_type(session->params.device.type)));
}
else if (key == HdCyclesRenderSettingsTokens->threads) {
return VtValue(session->params.threads);
}
else if (key == HdCyclesRenderSettingsTokens->time_limit) {
else if (key == HdCyclesRenderSettingsTokens->timeLimit) {
return VtValue(session->params.time_limit);
}
else if (key == HdCyclesRenderSettingsTokens->samples) {
return VtValue(session->params.samples);
}
else if (key == HdCyclesRenderSettingsTokens->sample_offset) {
else if (key == HdCyclesRenderSettingsTokens->sampleOffset) {
return VtValue(session->params.sample_offset);
}
else {

View File

@ -117,10 +117,11 @@ void HdCyclesRenderPass::_Execute(const HdRenderPassStateSharedPtr &renderPassSt
#endif
if (const auto camera = static_cast<const HdCyclesCamera *>(renderPassState->GetCamera())) {
camera->ApplyCameraSettings(scene->camera);
camera->ApplyCameraSettings(_renderParam, scene->camera);
}
else {
HdCyclesCamera::ApplyCameraSettings(renderPassState->GetWorldToViewMatrix(),
HdCyclesCamera::ApplyCameraSettings(_renderParam,
renderPassState->GetWorldToViewMatrix(),
renderPassState->GetProjectionMatrix(),
renderPassState->GetClipPlanes(),
scene->camera);

View File

@ -29,6 +29,16 @@ class HdCyclesSession final : public PXR_NS::HdRenderParam {
void UpdateScene();
double GetStageMetersPerUnit() const
{
return _stageMetersPerUnit;
}
void SetStageMetersPerUnit(double stageMetersPerUnit)
{
_stageMetersPerUnit = stageMetersPerUnit;
}
PXR_NS::HdRenderPassAovBinding GetDisplayAovBinding() const
{
return _displayAovBinding;
@ -52,6 +62,7 @@ class HdCyclesSession final : public PXR_NS::HdRenderParam {
private:
const bool _ownCyclesSession;
double _stageMetersPerUnit = 0.01;
PXR_NS::HdRenderPassAovBindingVector _aovBindings;
PXR_NS::HdRenderPassAovBinding _displayAovBinding;
};

View File

@ -355,6 +355,9 @@ void PathTrace::path_trace(RenderWork &render_work)
const int num_works = path_trace_works_.size();
tbb::task_group_context *tbb_ctx = tbb::task::self().group();
tbb_ctx->capture_fp_settings();
tbb::parallel_for(0, num_works, [&](int i) {
const double work_start_time = time_dt();
const int num_samples = render_work.path_trace.num_samples;

View File

@ -32,7 +32,7 @@ ccl_device void svm_node_aov_color(KernelGlobals kg,
kernel_data.film.pass_stride;
ccl_global float *buffer = render_buffer + render_buffer_offset +
(kernel_data.film.pass_aov_color + node.z);
kernel_write_pass_float3(buffer, make_float3(val.x, val.y, val.z));
kernel_write_pass_float4(buffer, make_float4(val.x, val.y, val.z, 1.0f));
}
}

View File

@ -690,12 +690,16 @@ void Mesh::pack_shaders(Scene *scene, uint *tri_shader)
bool last_smooth = false;
size_t triangles_size = num_triangles();
int *shader_ptr = shader.data();
const int *shader_ptr = shader.data();
const bool *smooth_ptr = smooth.data();
for (size_t i = 0; i < triangles_size; i++) {
if (shader_ptr[i] != last_shader || last_smooth != smooth[i]) {
last_shader = shader_ptr[i];
last_smooth = smooth[i];
const int new_shader = shader_ptr ? shader_ptr[i] : INT_MAX;
const bool new_smooth = smooth_ptr ? smooth_ptr[i] : false;
if (new_shader != last_shader || last_smooth != new_smooth) {
last_shader = new_shader;
last_smooth = new_smooth;
Shader *shader = (last_shader < used_shaders.size()) ?
static_cast<Shader *>(used_shaders[last_shader]) :
scene->default_surface;

View File

@ -321,7 +321,7 @@ PassInfo Pass::get_info(const PassType type, const bool include_albedo, const bo
break;
case PASS_AOV_COLOR:
pass_info.num_components = 3;
pass_info.num_components = 4;
break;
case PASS_AOV_VALUE:
pass_info.num_components = 1;

View File

@ -32,6 +32,12 @@
# define SIMD_SET_FLUSH_TO_ZERO \
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); \
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
#elif defined(__aarch64__) || defined(_M_ARM64)
# define _MM_FLUSH_ZERO_ON 24
# define __get_fpcr(__fpcr) __asm__ __volatile__("mrs %0,fpcr" : "=r"(__fpcr))
# define __set_fpcr(__fpcr) __asm__ __volatile__("msr fpcr,%0" : : "ri"(__fpcr))
# define SIMD_SET_FLUSH_TO_ZERO set_fz(_MM_FLUSH_ZERO_ON);
# define SIMD_GET_FLUSH_TO_ZERO get_fz(_MM_FLUSH_ZERO_ON)
#else
# define SIMD_SET_FLUSH_TO_ZERO
#endif
@ -104,6 +110,23 @@ static struct PosInfTy {
static struct StepTy {
} step ccl_attr_maybe_unused;
#endif
#if defined(__aarch64__) || defined(_M_ARM64)
__forceinline int set_fz(uint32_t flag)
{
uint64_t old_fpcr, new_fpcr;
__get_fpcr(old_fpcr);
new_fpcr = old_fpcr | (1ULL << flag);
__set_fpcr(new_fpcr);
__get_fpcr(old_fpcr);
return old_fpcr == new_fpcr;
}
__forceinline int get_fz(uint32_t flag)
{
uint64_t cur_fpcr;
__get_fpcr(cur_fpcr);
return (cur_fpcr & (1ULL << flag)) > 0 ? 1 : 0;
}
#endif
/* Utilities used by Neon */

View File

@ -461,12 +461,13 @@ OCIO_ConstProcessorRcPtr *FallbackImpl::createDisplayProcessor(OCIO_ConstConfigR
const char * /*display*/,
const char * /*look*/,
const float scale,
const float exponent)
const float exponent,
const bool inverse)
{
FallbackTransform transform;
transform.type = TRANSFORM_LINEAR_TO_SRGB;
transform.scale = scale;
transform.exponent = exponent;
transform.type = (inverse) ? TRANSFORM_SRGB_TO_LINEAR : TRANSFORM_LINEAR_TO_SRGB;
transform.scale = (inverse && scale != 0.0f) ? 1.0f / scale : scale;
transform.exponent = (inverse && exponent != 0.0f) ? 1.0f / exponent : exponent;
return (OCIO_ConstProcessorRcPtr *)new FallbackProcessor(transform);
}

View File

@ -250,9 +250,11 @@ OCIO_ConstProcessorRcPtr *OCIO_createDisplayProcessor(OCIO_ConstConfigRcPtr *con
const char *display,
const char *look,
const float scale,
const float exponent)
const float exponent,
const bool inverse)
{
return impl->createDisplayProcessor(config, input, view, display, look, scale, exponent);
return impl->createDisplayProcessor(
config, input, view, display, look, scale, exponent, inverse);
}
OCIO_PackedImageDesc *OCIO_createOCIO_PackedImageDesc(float *data,

View File

@ -166,7 +166,8 @@ OCIO_ConstProcessorRcPtr *OCIO_createDisplayProcessor(OCIO_ConstConfigRcPtr *con
const char *display,
const char *look,
const float scale,
const float exponent);
const float exponent,
const bool inverse);
OCIO_PackedImageDesc *OCIO_createOCIO_PackedImageDesc(float *data,
long width,

View File

@ -254,7 +254,12 @@ const char *OCIOImpl::configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr *conf
const char *view)
{
try {
return (*(ConstConfigRcPtr *)config)->getDisplayViewColorSpaceName(display, view);
const char *name = (*(ConstConfigRcPtr *)config)->getDisplayViewColorSpaceName(display, view);
/* OpenColorIO does not resolve this token for us, so do it ourselves. */
if (strcasecmp(name, "<USE_DISPLAY_NAME>") == 0) {
return display;
}
return name;
}
catch (Exception &exception) {
OCIO_reportException(exception);
@ -655,7 +660,8 @@ OCIO_ConstProcessorRcPtr *OCIOImpl::createDisplayProcessor(OCIO_ConstConfigRcPtr
const char *display,
const char *look,
const float scale,
const float exponent)
const float exponent,
const bool inverse)
{
ConstConfigRcPtr config = *(ConstConfigRcPtr *)config_;
@ -718,6 +724,10 @@ OCIO_ConstProcessorRcPtr *OCIOImpl::createDisplayProcessor(OCIO_ConstConfigRcPtr
group->appendTransform(et);
}
if (inverse) {
group->setDirection(TRANSFORM_DIR_INVERSE);
}
/* Create processor from transform. This is the moment were OCIO validates
* the entire transform, no need to check for the validity of inputs above. */
ConstProcessorRcPtr *p = MEM_new<ConstProcessorRcPtr>(__func__);

View File

@ -85,7 +85,8 @@ class IOCIOImpl {
const char *display,
const char *look,
const float scale,
const float exponent) = 0;
const float exponent,
const bool inverse) = 0;
virtual OCIO_PackedImageDesc *createOCIO_PackedImageDesc(float *data,
long width,
@ -201,7 +202,8 @@ class FallbackImpl : public IOCIOImpl {
const char *display,
const char *look,
const float scale,
const float exponent);
const float exponent,
const bool inverse);
OCIO_PackedImageDesc *createOCIO_PackedImageDesc(float *data,
long width,
@ -290,7 +292,8 @@ class OCIOImpl : public IOCIOImpl {
const char *display,
const char *look,
const float scale,
const float exponent);
const float exponent,
const bool inverse);
OCIO_PackedImageDesc *createOCIO_PackedImageDesc(float *data,
long width,

View File

@ -603,7 +603,7 @@ static OCIO_GPUDisplayShader &getGPUDisplayShader(
OCIO_ConstProcessorRcPtr *processor_to_scene_linear = OCIO_configGetProcessorWithNames(
config, input, ROLE_SCENE_LINEAR);
OCIO_ConstProcessorRcPtr *processor_to_display = OCIO_createDisplayProcessor(
config, ROLE_SCENE_LINEAR, view, display, look, 1.0f, 1.0f);
config, ROLE_SCENE_LINEAR, view, display, look, 1.0f, 1.0f, false);
/* Create shader descriptions. */
if (processor_to_scene_linear && processor_to_display) {

View File

@ -40,7 +40,7 @@ size_t count_utf_8_from_16(const wchar_t *string16)
}
else {
if (u < 0xE000) {
/*illegal*/;
/* Illegal. */
}
else {
count += 3;

View File

@ -173,7 +173,7 @@ colorspaces:
name: Non-Color
family: raw
description: |
Color space used for images which contains non-color data (i,e, normal maps)
Color space used for images which contains non-color data (i.e. normal maps)
equalitygroup:
bitdepth: 32f
isdata: true

View File

@ -424,6 +424,13 @@ def dump_rna_messages(msgs, reports, settings, verbose=False):
# Recursively process subclasses.
process_cls_list(cls.__subclasses__())
# FIXME Workaround weird new (blender 3.2) issue where some classes (like `bpy.types.Modifier`)
# are not listed by `bpy.types.ID.__base__.__subclasses__()` until they are accessed from
# `bpy.types` (eg just executing `bpy.types.Modifier`).
cls_dir = dir(bpy.types)
for cls_name in cls_dir:
getattr(bpy.types, cls_name)
# Parse everything (recursively parsing from bpy_struct "class"...).
process_cls_list(bpy.types.ID.__base__.__subclasses__())

File diff suppressed because it is too large Load Diff

View File

@ -944,7 +944,7 @@ def km_markers(params):
*_template_items_select_actions(params, "marker.select_all"),
("marker.delete", {"type": 'X', "value": 'PRESS'}, None),
("marker.delete", {"type": 'DEL', "value": 'PRESS'}, None),
("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None),
op_panel("TOPBAR_PT_name_marker", {"type": 'F2', "value": 'PRESS'}, [("keep_open", False)]),
("marker.move", {"type": 'G', "value": 'PRESS'}, None),
("marker.camera_bind", {"type": 'B', "value": 'PRESS', "ctrl": True}, None),
])
@ -1267,7 +1267,8 @@ def km_view3d(params):
("view3d.localview", {"type": 'NUMPAD_SLASH', "value": 'PRESS'}, None),
("view3d.localview", {"type": 'SLASH', "value": 'PRESS'}, None),
("view3d.localview", {"type": 'MOUSESMARTZOOM', "value": 'ANY'}, None),
("view3d.localview_remove_from", {"type": 'M', "value": 'PRESS'}, None),
("view3d.localview_remove_from", {"type": 'NUMPAD_SLASH', "value": 'PRESS', "alt": True}, None),
("view3d.localview_remove_from", {"type": 'SLASH', "value": 'PRESS', "alt": True}, None),
# Navigation.
("view3d.rotate", {"type": 'MOUSEROTATE', "value": 'ANY'}, None),
*((("view3d.rotate", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "shift": True}, None),
@ -1792,8 +1793,8 @@ def km_graph_editor(params):
("transform.resize", {"type": 'S', "value": 'PRESS'}, None),
*_template_items_proportional_editing(params, connected=False, toggle_data_path='tool_settings.use_proportional_fcurve'),
("marker.add", {"type": 'M', "value": 'PRESS'}, None),
("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None),
*_template_items_context_menu("GRAPH_MT_context_menu", params.context_menu_event),])
*_template_items_context_menu("GRAPH_MT_context_menu", params.context_menu_event),
])
if not params.legacy:
items.extend([op_menu_pie("GRAPH_MT_pivot_pie", {"type": 'PERIOD', "value": 'PRESS'}),])
@ -2375,7 +2376,6 @@ def km_dopesheet(params):
{"properties": [("mode", 'TIME_SLIDE')]}),
*_template_items_proportional_editing(params, connected=False, toggle_data_path='tool_settings.use_proportional_action'),
("marker.add", {"type": 'M', "value": 'PRESS'}, None),
("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None),
("marker.camera_bind", {"type": 'B', "value": 'PRESS', "ctrl": True}, None),
*_template_items_context_menu("DOPESHEET_MT_context_menu", params.context_menu_event),
*_template_items_change_frame(params),])
@ -2392,8 +2392,12 @@ def km_nla_generic(_params):
{"space_type": 'NLA_EDITOR', "region_type": 'WINDOW'},
{"items": items},)
items.extend([*_template_space_region_type_toggle(sidebar_key={"type": 'N', "value": 'PRESS'},),
("nla.tweakmode_enter", {"type": 'TAB', "value": 'PRESS'}, None),
items.extend([
*_template_space_region_type_toggle(
sidebar_key={"type": 'N', "value": 'PRESS'},
),
("nla.tweakmode_enter", {"type": 'TAB', "value": 'PRESS'},
{"properties": [("use_upper_stack_evaluation", False)]}),
("nla.tweakmode_exit", {"type": 'TAB', "value": 'PRESS'}, None),
("nla.tweakmode_enter", {"type": 'TAB', "value": 'PRESS', "shift": True},
{"properties": [("isolate_action", True)]}),
@ -2494,7 +2498,6 @@ def km_nla_editor(params):
("transform.transform", {"type": 'S', "value": 'PRESS'},
{"properties": [("mode", 'TIME_SCALE')]}),
("marker.add", {"type": 'M', "value": 'PRESS'}, None),
("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None),
*_template_items_context_menu("NLA_MT_context_menu", params.context_menu_event),
*_template_items_change_frame(params),])
@ -2771,7 +2774,6 @@ def km_sequencer(params):
("transform.transform", {"type": 'E', "value": 'PRESS'},
{"properties": [("mode", 'TIME_EXTEND')]}),
("marker.add", {"type": 'M', "value": 'PRESS'}, None),
("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None),
("sequencer.select_side_of_frame", {"type": 'LEFT_BRACKET', "value": 'PRESS'},
{"properties": [("side", 'LEFT')]}),
("sequencer.select_side_of_frame", {"type": 'RIGHT_BRACKET', "value": 'PRESS'},

View File

@ -836,7 +836,7 @@ def km_markers(params):
("marker.select_all", {"type": 'I', "value": 'PRESS', "ctrl": True}, {"properties": [("action", 'INVERT')]}),
("marker.delete", {"type": 'BACK_SPACE', "value": 'PRESS'}, None),
("marker.delete", {"type": 'DEL', "value": 'PRESS'}, None),
("marker.rename", {"type": 'RET', "value": 'PRESS'}, None),
op_panel("TOPBAR_PT_name_marker", {"type": 'RET', "value": 'PRESS'}, [("keep_open", False)]),
("marker.move", {"type": 'W', "value": 'PRESS'}, None),
])
@ -937,7 +937,6 @@ def km_graph_editor(params):
("wm.context_menu_enum", {"type": 'X', "value": 'PRESS'},
{"properties": [("data_path", 'space_data.auto_snap')]}),
("marker.add", {"type": 'M', "value": 'PRESS'}, None),
("marker.rename", {"type": 'RET', "value": 'PRESS'}, None),
op_menu_pie("GRAPH_MT_snap_pie", {"type": 'X', "value": 'PRESS', "shift": True}),
])
@ -1438,7 +1437,6 @@ def km_dopesheet(params):
("wm.context_toggle", {"type": 'B', "value": 'PRESS'},
{"properties": [("data_path", 'tool_settings.use_proportional_action')]}),
("marker.add", {"type": 'M', "value": 'PRESS'}, None),
("marker.rename", {"type": 'RET', "value": 'PRESS'}, None),
("anim.start_frame_set", {"type": 'LEFT_ARROW', "value": 'PRESS', "ctrl": True}, None),
("anim.end_frame_set", {"type": 'RIGHT_ARROW', "value": 'PRESS', "ctrl": True}, None),
])
@ -1548,7 +1546,6 @@ def km_nla_editor(params):
*_template_items_context_menu("NLA_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
op_menu_pie("NLA_MT_snap_pie", {"type": 'X', "value": 'PRESS', "shift": True}),
("marker.add", {"type": 'M', "value": 'PRESS'}, None),
("marker.rename", {"type": 'RET', "value": 'PRESS'}, None),
])
return keymap
@ -1835,7 +1832,6 @@ def km_sequencer(params):
{"properties": [("mode", 'TIME_EXTEND')]}),
*_template_items_context_menu("SEQUENCER_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
("marker.add", {"type": 'M', "value": 'PRESS'}, None),
("marker.rename", {"type": 'RET', "value": 'PRESS'}, None),
# Tools
op_tool_cycle("builtin.select_box", {"type": 'Q', "value": 'PRESS'}),
op_tool_cycle("builtin.blade", {"type": 'B', "value": 'PRESS'}),

View File

@ -73,7 +73,11 @@ class NodeAddOperator:
for n in tree.nodes:
n.select = False
node = tree.nodes.new(type=node_type)
try:
node = tree.nodes.new(type=node_type)
except RuntimeError as e:
self.report({'ERROR'}, str(e))
return None
for setting in self.settings:
# XXX catch exceptions here?

View File

@ -177,7 +177,7 @@ class DATA_PT_pose_library(ArmatureButtonsPanel, Panel):
col.label(text="which was replaced by the Asset Browser.")
url = self.get_manual_url()
col.operator('wm.url_open', text="More Info", icon="URL").url = url
col.operator("wm.url_open", text="More Info", icon='URL').url = url
layout.separator()
@ -188,12 +188,12 @@ class DATA_PT_pose_library(ArmatureButtonsPanel, Panel):
col.template_ID(ob, "pose_library", new="poselib.new", unlink="poselib.unlink")
if poselib:
if hasattr(bpy.types, 'POSELIB_OT_convert_old_object_poselib'):
col.operator('poselib.convert_old_object_poselib',
text="Convert to Pose Assets", icon="ASSET_MANAGER")
if hasattr(bpy.types, "POSELIB_OT_convert_old_object_poselib"):
col.operator("poselib.convert_old_object_poselib",
text="Convert to Pose Assets", icon='ASSET_MANAGER')
else:
col.label(text="Enable the Pose Library add-on to convert", icon="ERROR")
col.label(text="this legacy pose library to pose assets.", icon="BLANK1")
col.label(text="Enable the Pose Library add-on to convert", icon='ERROR')
col.label(text="this legacy pose library to pose assets.", icon='BLANK1')
# Put the deprecated stuff in its own sub-layout.
@ -202,7 +202,10 @@ class DATA_PT_pose_library(ArmatureButtonsPanel, Panel):
# warning about poselib being in an invalid state
if poselib.fcurves and not poselib.pose_markers:
dep_layout.label(icon='ERROR', text="Error: Potentially corrupt library, run 'Sanitize' operator to fix")
dep_layout.label(
icon='ERROR',
text="Error: Potentially corrupt library, run 'Sanitize' operator to fix",
)
# list of poses in pose library
row = dep_layout.row()

View File

@ -605,21 +605,22 @@ class MESH_UL_color_attributes(UIList, ColorAttributesListBase):
split.emboss = 'NONE'
split.prop(attribute, "name", text="")
active_render = _index == data.color_attributes.render_color_index
props = split.operator(
"geometry.color_attribute_render_set",
text="",
icon='RESTRICT_RENDER_OFF' if active_render else 'RESTRICT_RENDER_ON',
)
props.name = attribute.name
sub = split.row()
sub.alignment = 'RIGHT'
sub.active = False
sub.label(text="%s%s" % (domain_name, data_type.name))
active_render = _index == data.color_attributes.render_color_index
row = layout.row()
row.emboss = 'NONE'
prop = row.operator(
"geometry.color_attribute_render_set",
text="",
icon='RESTRICT_RENDER_OFF' if active_render else 'RESTRICT_RENDER_ON',
)
prop.name = attribute.name
class MESH_UL_color_attributes_selector(UIList, ColorAttributesListBase):
def draw_item(self, _context, layout, data, attribute, _icon, _active_data, _active_propname, _index):

View File

@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# <pep8 compliant>
from bpy.types import Panel, UIList
from bpy.types import Menu, Panel, UIList
class VIEWLAYER_UL_aov(UIList):
@ -138,7 +138,7 @@ class ViewLayerAOVPanel(ViewLayerButtonsPanel, Panel):
row = layout.row()
col = row.column()
col.template_list("VIEWLAYER_UL_aov", "aovs", view_layer,
"aovs", view_layer, "active_aov_index", rows=2)
"aovs", view_layer, "active_aov_index", rows=3)
col = row.column()
sub = col.column(align=True)
@ -187,6 +187,16 @@ class VIEWLAYER_PT_layer_passes_cryptomatte(ViewLayerCryptomattePanel, Panel):
COMPAT_ENGINES = {'BLENDER_EEVEE'}
class VIEWLAYER_MT_lightgroup_sync(Menu):
bl_label = "Lightgroup Sync"
def draw(self, _context):
layout = self.layout
layout.operator("scene.view_layer_add_used_lightgroups", icon='ADD')
layout.operator("scene.view_layer_remove_unused_lightgroups", icon='REMOVE')
class ViewLayerLightgroupsPanel(ViewLayerButtonsPanel, Panel):
bl_label = "Light Groups"
@ -201,12 +211,14 @@ class ViewLayerLightgroupsPanel(ViewLayerButtonsPanel, Panel):
row = layout.row()
col = row.column()
col.template_list("UI_UL_list", "lightgroups", view_layer,
"lightgroups", view_layer, "active_lightgroup_index", rows=2)
"lightgroups", view_layer, "active_lightgroup_index", rows=3)
col = row.column()
sub = col.column(align=True)
sub.operator("scene.view_layer_add_lightgroup", icon='ADD', text="")
sub.operator("scene.view_layer_remove_lightgroup", icon='REMOVE', text="")
sub.separator()
sub.menu("VIEWLAYER_MT_lightgroup_sync", icon='DOWNARROW_HLT', text="")
class VIEWLAYER_PT_layer_passes_lightgroups(ViewLayerLightgroupsPanel):
@ -215,6 +227,7 @@ class VIEWLAYER_PT_layer_passes_lightgroups(ViewLayerLightgroupsPanel):
classes = (
VIEWLAYER_MT_lightgroup_sync,
VIEWLAYER_PT_layer,
VIEWLAYER_PT_layer_passes,
VIEWLAYER_PT_eevee_layer_passes_data,

View File

@ -1453,58 +1453,6 @@ class IMAGE_PT_uv_cursor(Panel):
col.prop(sima, "cursor_location", text="Location")
class IMAGE_PT_udim_grid(Panel):
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'UI'
bl_category = "View"
bl_label = "UDIM Grid"
@classmethod
def poll(cls, context):
sima = context.space_data
return sima.show_uvedit
def draw(self, context):
layout = self.layout
sima = context.space_data
uvedit = sima.uv_editor
layout.use_property_split = True
layout.use_property_decorate = False
col = layout.column()
col.prop(uvedit, "tile_grid_shape", text="Grid Shape")
class IMAGE_PT_custom_grid(Panel):
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'UI'
bl_category = "View"
bl_label = "Custom Grid"
@classmethod
def poll(cls, context):
sima = context.space_data
return sima.show_uvedit
def draw_header(self, context):
sima = context.space_data
uvedit = sima.uv_editor
self.layout.prop(uvedit, "use_custom_grid", text="")
def draw(self, context):
layout = self.layout
sima = context.space_data
uvedit = sima.uv_editor
layout.use_property_split = True
layout.use_property_decorate = False
col = layout.column()
col.prop(uvedit, "custom_grid_subdivisions", text="Subdivisions")
class IMAGE_PT_overlay(Panel):
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'HEADER'
@ -1515,6 +1463,49 @@ class IMAGE_PT_overlay(Panel):
pass
class IMAGE_PT_overlay_guides(Panel):
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'HEADER'
bl_label = "Guides"
bl_parent_id = 'IMAGE_PT_overlay'
@classmethod
def poll(cls, context):
sima = context.space_data
return sima.show_uvedit
def draw(self, context):
layout = self.layout
sima = context.space_data
overlay = sima.overlay
uvedit = sima.uv_editor
layout.active = overlay.show_overlays
row = layout.row()
row_el = row.column()
row_el.prop(overlay, "show_grid_background", text="Grid")
if overlay.show_grid_background:
layout.use_property_split = True
col = layout.column(align=False, heading="Fixed Subdivisions")
col.use_property_decorate = False
row = col.row(align=True)
sub = row.row(align=True)
sub.prop(uvedit, "use_custom_grid", text="")
sub = sub.row(align=True)
sub.active = uvedit.use_custom_grid
sub.prop(uvedit, "custom_grid_subdivisions", text="")
row = layout.row()
row.use_property_split = True
row.use_property_decorate = False
row.prop(uvedit, "tile_grid_shape", text="Tiles")
class IMAGE_PT_overlay_uv_edit(Panel):
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'HEADER'
@ -1689,9 +1680,8 @@ classes = (
IMAGE_PT_scope_sample,
IMAGE_PT_uv_cursor,
IMAGE_PT_annotation,
IMAGE_PT_udim_grid,
IMAGE_PT_custom_grid,
IMAGE_PT_overlay,
IMAGE_PT_overlay_guides,
IMAGE_PT_overlay_uv_edit,
IMAGE_PT_overlay_uv_edit_geometry,
IMAGE_PT_overlay_texture_paint,

View File

@ -150,6 +150,23 @@ class NLA_MT_marker(Menu):
marker_menu_generic(layout, context)
class NLA_MT_marker_select(Menu):
bl_label = 'Select'
def draw(self, context):
layout = self.layout
layout.operator("marker.select_all", text="All").action = 'SELECT'
layout.operator("marker.select_all", text="None").action = 'DESELECT'
layout.operator("marker.select_all", text="Invert").action = 'INVERT'
layout.separator()
layout.operator("marker.select_leftright", text="Before Current Frame").mode = 'LEFT'
layout.operator("marker.select_leftright", text="After Current Frame").mode = 'RIGHT'
class NLA_MT_edit(Menu):
bl_label = "Edit"
@ -197,7 +214,8 @@ class NLA_MT_edit(Menu):
layout.operator("nla.tweakmode_exit", text="Stop Tweaking Strip Actions")
else:
layout.operator("nla.tweakmode_enter", text="Start Editing Stashed Action").isolate_action = True
layout.operator("nla.tweakmode_enter", text="Start Tweaking Strip Actions")
layout.operator("nla.tweakmode_enter", text="Start Tweaking Strip Actions (Full Stack)").use_upper_stack_evaluation = True
layout.operator("nla.tweakmode_enter", text="Start Tweaking Strip Actions (Lower Stack)").use_upper_stack_evaluation = False
class NLA_MT_add(Menu):
@ -271,7 +289,8 @@ class NLA_MT_context_menu(Menu):
layout.operator("nla.tweakmode_exit", text="Stop Tweaking Strip Actions")
else:
layout.operator("nla.tweakmode_enter", text="Start Editing Stashed Action").isolate_action = True
layout.operator("nla.tweakmode_enter", text="Start Tweaking Strip Actions")
layout.operator("nla.tweakmode_enter", text="Start Tweaking Strip Actions (Full Stack)").use_upper_stack_evaluation = True
layout.operator("nla.tweakmode_enter", text="Start Tweaking Strip Actions (Lower Stack)").use_upper_stack_evaluation = False
layout.separator()
@ -312,6 +331,7 @@ classes = (
NLA_MT_view,
NLA_MT_select,
NLA_MT_marker,
NLA_MT_marker_select,
NLA_MT_add,
NLA_MT_edit_transform,
NLA_MT_snap_pie,

View File

@ -709,6 +709,7 @@ class NODE_PT_overlay(Panel):
if snode.tree_type == 'GeometryNodeTree':
col.separator()
col.prop(overlay, "show_timing", text="Timings")
col.prop(overlay, "show_named_attributes", text="Named Attributes")
class NODE_UL_interface_sockets(bpy.types.UIList):

View File

@ -187,11 +187,17 @@ def marker_menu_generic(layout, context):
layout.separator()
layout.operator("marker.rename", text="Rename Marker")
props = layout.operator("wm.call_panel", text="Rename Marker")
props.name = "TOPBAR_PT_name_marker"
props.keep_open = False
layout.operator("marker.move", text="Move Marker")
layout.separator()
layout.menu('NLA_MT_marker_select')
layout.separator()
layout.operator("marker.camera_bind")
layout.separator()

View File

@ -851,6 +851,64 @@ class TOPBAR_PT_name(Panel):
row.label(text="No active item")
class TOPBAR_PT_name_marker(Panel):
bl_space_type = 'TOPBAR' # dummy
bl_region_type = 'HEADER'
bl_label = "Rename Marker"
bl_ui_units_x = 14
@staticmethod
def is_using_pose_markers(context):
sd = context.space_data
return (sd.type == 'DOPESHEET_EDITOR' and sd.mode in {'ACTION', 'SHAPEKEY'} and
sd.show_pose_markers and sd.action)
@staticmethod
def get_selected_marker(context):
if TOPBAR_PT_name_marker.is_using_pose_markers(context):
markers = context.space_data.action.pose_markers
else:
markers = context.scene.timeline_markers
for marker in markers:
if marker.select:
return marker
return None
@staticmethod
def row_with_icon(layout, icon):
row = layout.row()
row.activate_init = True
row.label(icon=icon)
return row
def draw(self, context):
layout = self.layout
layout.label(text="Marker Name")
scene = context.scene
if scene.tool_settings.lock_markers:
row = self.row_with_icon(layout, 'ERROR')
label = "Markers are locked"
row.label(text=label)
return
marker = self.get_selected_marker(context)
if marker is None:
row = self.row_with_icon(layout, 'ERROR')
row.label(text="No active marker")
return
icon = 'TIME'
if marker.camera is not None:
icon = 'CAMERA_DATA'
elif self.is_using_pose_markers(context):
icon = 'ARMATURE_DATA'
row = self.row_with_icon(layout, icon)
row.prop(marker, "name", text="")
classes = (
TOPBAR_HT_upper_bar,
TOPBAR_MT_file_context_menu,
@ -877,6 +935,7 @@ classes = (
TOPBAR_PT_gpencil_layers,
TOPBAR_PT_gpencil_primitive,
TOPBAR_PT_name,
TOPBAR_PT_name_marker,
)
if __name__ == "__main__": # only for live edit.

View File

@ -2219,7 +2219,8 @@ class USERPREF_PT_experimental_prototypes(ExperimentalPanel, Panel):
),
)
# Keep this as tweaks can be useful to restore.
"""
class USERPREF_PT_experimental_tweaks(ExperimentalPanel, Panel):
bl_label = "Tweaks"
@ -2230,6 +2231,7 @@ class USERPREF_PT_experimental_tweaks(ExperimentalPanel, Panel):
),
)
"""
class USERPREF_PT_experimental_debugging(ExperimentalPanel, Panel):
bl_label = "Debugging"
@ -2349,7 +2351,7 @@ classes = (USERPREF_PT_theme_user_interface,
USERPREF_PT_experimental_new_features,
USERPREF_PT_experimental_prototypes,
USERPREF_PT_experimental_tweaks,
# USERPREF_PT_experimental_tweaks,
USERPREF_PT_experimental_debugging,
# Add dynamically generated editor theme panels last,

View File

@ -2715,6 +2715,9 @@ class VIEW3D_MT_object_apply(Menu):
text="Visual Geometry to Mesh",
text_ctxt=i18n_contexts.default,).target = 'MESH'
layout.operator("object.duplicates_make_real")
layout.operator("object.parent_inverse_apply",
text="Parent Inverse",
text_ctxt=i18n_contexts.default)
class VIEW3D_MT_object_parent(Menu):
@ -6722,8 +6725,10 @@ class VIEW3D_PT_snapping(Panel):
col.prop(tool_settings, "use_snap_backface_culling")
if obj:
if object_mode == 'EDIT':
col.prop(tool_settings, "use_snap_self")
if object_mode == 'EDIT' and obj.type not in {'LATTICE', 'META', 'FONT'}:
sub = col.column()
sub.active = not (tool_settings.use_proportional_edit and obj.type == 'MESH')
sub.prop(tool_settings, "use_snap_self")
if object_mode in {'OBJECT', 'POSE', 'EDIT', 'WEIGHT_PAINT'}:
col.prop(tool_settings, "use_snap_align_rotation")

View File

@ -109,7 +109,7 @@ typedef bool (*BLF_GlyphBoundsFn)(const char *str,
size_t str_step_ofs,
const struct rcti *glyph_step_bounds,
int glyph_advance_x,
const struct rctf *glyph_bounds,
const struct rcti *glyph_bounds,
const int glyph_bearing[2],
void *user_data);
@ -151,9 +151,9 @@ size_t BLF_width_to_rstrlen(
void BLF_boundbox_ex(int fontid,
const char *str,
size_t str_len,
struct rctf *box,
struct rcti *box,
struct ResultBLF *r_info) ATTR_NONNULL(2);
void BLF_boundbox(int fontid, const char *str, size_t str_len, struct rctf *box) ATTR_NONNULL();
void BLF_boundbox(int fontid, const char *str, size_t str_len, struct rcti *box) ATTR_NONNULL();
/**
* The next both function return the width and height
@ -173,9 +173,9 @@ float BLF_height(int fontid, const char *str, size_t str_len) ATTR_WARN_UNUSED_R
* Return dimensions of the font without any sample text.
*/
int BLF_height_max(int fontid) ATTR_WARN_UNUSED_RESULT;
float BLF_width_max(int fontid) ATTR_WARN_UNUSED_RESULT;
float BLF_descender(int fontid) ATTR_WARN_UNUSED_RESULT;
float BLF_ascender(int fontid) ATTR_WARN_UNUSED_RESULT;
int BLF_width_max(int fontid) ATTR_WARN_UNUSED_RESULT;
int BLF_descender(int fontid) ATTR_WARN_UNUSED_RESULT;
int BLF_ascender(int fontid) ATTR_WARN_UNUSED_RESULT;
/**
* The following function return the width and height of the string, but
@ -195,7 +195,7 @@ float BLF_fixed_width(int fontid) ATTR_WARN_UNUSED_RESULT;
* have to be enable/disable using BLF_enable/disable.
*/
void BLF_rotation(int fontid, float angle);
void BLF_clipping(int fontid, float xmin, float ymin, float xmax, float ymax);
void BLF_clipping(int fontid, int xmin, int ymin, int xmax, int ymax);
void BLF_wordwrap(int fontid, int wrap_width);
#if BLF_BLUR_ENABLE

View File

@ -342,9 +342,9 @@ void BLF_position(int fontid, float x, float y, float z)
}
}
font->pos[0] = x;
font->pos[1] = y;
font->pos[2] = z;
font->pos[0] = round_fl_to_int(x);
font->pos[1] = round_fl_to_int(y);
font->pos[2] = round_fl_to_int(z);
}
}
@ -488,7 +488,7 @@ static void blf_draw_gl__start(FontBLF *font)
GPU_matrix_mul(font->m);
}
GPU_matrix_translate_3fv(font->pos);
GPU_matrix_translate_3f(font->pos[0], font->pos[1], font->pos[2]);
if (font->flags & BLF_ASPECT) {
GPU_matrix_scale_3fv(font->aspect);
@ -589,9 +589,10 @@ size_t BLF_width_to_strlen(
if (font) {
const float xa = (font->flags & BLF_ASPECT) ? font->aspect[0] : 1.0f;
size_t ret;
ret = blf_font_width_to_strlen(font, str, str_len, width / xa, r_width);
int width_result;
ret = blf_font_width_to_strlen(font, str, str_len, width / xa, &width_result);
if (r_width) {
*r_width *= xa;
*r_width = (float)width_result * xa;
}
return ret;
}
@ -610,9 +611,10 @@ size_t BLF_width_to_rstrlen(
if (font) {
const float xa = (font->flags & BLF_ASPECT) ? font->aspect[0] : 1.0f;
size_t ret;
ret = blf_font_width_to_rstrlen(font, str, str_len, width / xa, r_width);
int width_result;
ret = blf_font_width_to_rstrlen(font, str, str_len, width / xa, &width_result);
if (r_width) {
*r_width *= xa;
*r_width = (float)width_result * xa;
}
return ret;
}
@ -624,7 +626,7 @@ size_t BLF_width_to_rstrlen(
}
void BLF_boundbox_ex(
int fontid, const char *str, const size_t str_len, rctf *r_box, struct ResultBLF *r_info)
int fontid, const char *str, const size_t str_len, rcti *r_box, struct ResultBLF *r_info)
{
FontBLF *font = blf_get(fontid);
@ -640,7 +642,7 @@ void BLF_boundbox_ex(
}
}
void BLF_boundbox(int fontid, const char *str, const size_t str_len, rctf *r_box)
void BLF_boundbox(int fontid, const char *str, const size_t str_len, rcti *r_box)
{
BLF_boundbox_ex(fontid, str, str_len, r_box, NULL);
}
@ -716,7 +718,7 @@ int BLF_height_max(int fontid)
return 0;
}
float BLF_width_max(int fontid)
int BLF_width_max(int fontid)
{
FontBLF *font = blf_get(fontid);
@ -724,10 +726,10 @@ float BLF_width_max(int fontid)
return blf_font_width_max(font);
}
return 0.0f;
return 0;
}
float BLF_descender(int fontid)
int BLF_descender(int fontid)
{
FontBLF *font = blf_get(fontid);
@ -735,10 +737,10 @@ float BLF_descender(int fontid)
return blf_font_descender(font);
}
return 0.0f;
return 0;
}
float BLF_ascender(int fontid)
int BLF_ascender(int fontid)
{
FontBLF *font = blf_get(fontid);
@ -758,7 +760,7 @@ void BLF_rotation(int fontid, float angle)
}
}
void BLF_clipping(int fontid, float xmin, float ymin, float xmax, float ymax)
void BLF_clipping(int fontid, int xmin, int ymin, int xmax, int ymax)
{
FontBLF *font = blf_get(fontid);
@ -889,7 +891,7 @@ void BLF_state_print(int fontid)
printf(" name: '%s'\n", font->name);
printf(" size: %f\n", font->size);
printf(" dpi: %u\n", font->dpi);
printf(" pos: %.6f %.6f %.6f\n", UNPACK3(font->pos));
printf(" pos: %d %d %d\n", UNPACK3(font->pos));
printf(" aspect: (%d) %.6f %.6f %.6f\n",
(font->flags & BLF_ROTATION) != 0,
UNPACK3(font->aspect));

View File

@ -57,34 +57,26 @@ static SpinLock blf_glyph_cache_mutex;
/* May be set to #UI_widgetbase_draw_cache_flush. */
static void (*blf_draw_cache_flush)(void) = NULL;
static ft_pix blf_font_height_max_ft_pix(struct FontBLF *font);
static ft_pix blf_font_width_max_ft_pix(struct FontBLF *font);
/* -------------------------------------------------------------------- */
/** \name FreeType Utilities (Internal)
* \{ */
/**
* Convert a FreeType 26.6 value representing an unscaled design size to pixels.
* This is an exact copy of the scaling done inside FT_Get_Kerning when called
* with #FT_KERNING_DEFAULT, including arbitrary resizing for small fonts.
*/
static int blf_unscaled_F26Dot6_to_pixels(FontBLF *font, FT_Pos value)
/* Convert a FreeType 26.6 value representing an unscaled design size to factional pixels. */
static ft_pix blf_unscaled_F26Dot6_to_pixels(FontBLF *font, FT_Pos value)
{
/* Scale value by font size using integer-optimized multiplication. */
FT_Long scaled = FT_MulFix(value, font->face->size->metrics.x_scale);
/* FreeType states that this '25' has been determined heuristically. */
/* Copied from FreeType's FT_Get_Kerning (with FT_KERNING_DEFAULT), scaling down */
/* kerning distances at small ppem values so that they don't become too big. */
if (font->face->size->metrics.x_ppem < 25) {
scaled = FT_MulDiv(scaled, font->face->size->metrics.x_ppem, 25);
}
/* Copies of internal FreeType macros needed here. */
#define FT_PIX_FLOOR(x) ((x) & ~63)
#define FT_PIX_ROUND(x) FT_PIX_FLOOR((x) + 32)
/* Round to even 64ths, then divide by 64. */
return (int)FT_PIX_ROUND(scaled) >> 6;
#undef FT_PIX_FLOOR
#undef FT_PIX_ROUND
return (ft_pix)scaled;
}
/** \} */
@ -146,12 +138,12 @@ void blf_batch_draw_begin(FontBLF *font)
if (simple_shader) {
/* Offset is applied to each glyph. */
g_batch.ofs[0] = floorf(font->pos[0]);
g_batch.ofs[1] = floorf(font->pos[1]);
g_batch.ofs[0] = font->pos[0];
g_batch.ofs[1] = font->pos[1];
}
else {
/* Offset is baked in modelview mat. */
zero_v2(g_batch.ofs);
zero_v2_int(g_batch.ofs);
}
if (g_batch.active) {
@ -293,36 +285,39 @@ BLI_INLINE GlyphBLF *blf_glyph_from_utf8_and_step(
return blf_glyph_ensure(font, gc, charcode);
}
BLI_INLINE int blf_kerning(FontBLF *font, const GlyphBLF *g_prev, const GlyphBLF *g)
BLI_INLINE ft_pix blf_kerning(FontBLF *font, const GlyphBLF *g_prev, const GlyphBLF *g)
{
if (!FT_HAS_KERNING(font->face) || g_prev == NULL) {
return 0;
ft_pix adjustment = 0;
/* Small adjust if there is hinting. */
adjustment += g->lsb_delta - ((g_prev) ? g_prev->rsb_delta : 0);
if (FT_HAS_KERNING(font->face) && g_prev) {
FT_Vector delta = {KERNING_ENTRY_UNSET};
/* Get unscaled kerning value from our cache if ASCII. */
if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < GLYPH_ASCII_TABLE_SIZE)) {
delta.x = font->kerning_cache->ascii_table[g->c][g_prev->c];
}
/* If not ASCII or not found in cache, ask FreeType for kerning. */
if (UNLIKELY(delta.x == KERNING_ENTRY_UNSET)) {
/* Note that this function sets delta values to zero on any error. */
FT_Get_Kerning(font->face, g_prev->idx, g->idx, FT_KERNING_UNSCALED, &delta);
}
/* If ASCII we save this value to our cache for quicker access next time. */
if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < GLYPH_ASCII_TABLE_SIZE)) {
font->kerning_cache->ascii_table[g->c][g_prev->c] = (int)delta.x;
}
if (delta.x != 0) {
/* Convert unscaled design units to pixels and move pen. */
adjustment += blf_unscaled_F26Dot6_to_pixels(font, delta.x);
}
}
FT_Vector delta = {KERNING_ENTRY_UNSET};
/* Get unscaled kerning value from our cache if ASCII. */
if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < GLYPH_ASCII_TABLE_SIZE)) {
delta.x = font->kerning_cache->ascii_table[g->c][g_prev->c];
}
/* If not ASCII or not found in cache, ask FreeType for kerning. */
if (UNLIKELY(delta.x == KERNING_ENTRY_UNSET)) {
/* Note that this function sets delta values to zero on any error. */
FT_Get_Kerning(font->face, g_prev->idx, g->idx, FT_KERNING_UNSCALED, &delta);
}
/* If ASCII we save this value to our cache for quicker access next time. */
if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < GLYPH_ASCII_TABLE_SIZE)) {
font->kerning_cache->ascii_table[g->c][g_prev->c] = (int)delta.x;
}
if (delta.x != 0) {
/* Convert unscaled design units to pixels and move pen. */
return blf_unscaled_F26Dot6_to_pixels(font, delta.x);
}
return 0;
return adjustment;
}
/** \} */
@ -336,10 +331,10 @@ static void blf_font_draw_ex(FontBLF *font,
const char *str,
const size_t str_len,
struct ResultBLF *r_info,
int pen_y)
ft_pix pen_y)
{
GlyphBLF *g, *g_prev = NULL;
int pen_x = 0;
ft_pix pen_x = 0;
size_t i = 0;
if (str_len == 0) {
@ -358,9 +353,9 @@ static void blf_font_draw_ex(FontBLF *font,
pen_x += blf_kerning(font, g_prev, g);
/* do not return this loop if clipped, we want every character tested */
blf_glyph_draw(font, gc, g, (float)pen_x, (float)pen_y);
blf_glyph_draw(font, gc, g, ft_pix_to_int_floor(pen_x), ft_pix_to_int_floor(pen_y));
pen_x += g->advance_i;
pen_x = ft_pix_round_advance(pen_x, g->advance_x);
g_prev = g;
}
@ -368,7 +363,7 @@ static void blf_font_draw_ex(FontBLF *font,
if (r_info) {
r_info->lines = 1;
r_info->width = pen_x;
r_info->width = ft_pix_to_int(pen_x);
}
}
void blf_font_draw(FontBLF *font, const char *str, const size_t str_len, struct ResultBLF *r_info)
@ -382,7 +377,9 @@ int blf_font_draw_mono(FontBLF *font, const char *str, const size_t str_len, int
{
GlyphBLF *g;
int col, columns = 0;
int pen_x = 0, pen_y = 0;
ft_pix pen_x = 0, pen_y = 0;
ft_pix cwidth_fpx = ft_pix_from_int(cwidth);
size_t i = 0;
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
@ -396,7 +393,7 @@ int blf_font_draw_mono(FontBLF *font, const char *str, const size_t str_len, int
continue;
}
/* do not return this loop if clipped, we want every character tested */
blf_glyph_draw(font, gc, g, (float)pen_x, (float)pen_y);
blf_glyph_draw(font, gc, g, ft_pix_to_int_floor(pen_x), ft_pix_to_int_floor(pen_y));
col = BLI_wcwidth((char32_t)g->c);
if (col < 0) {
@ -404,7 +401,7 @@ int blf_font_draw_mono(FontBLF *font, const char *str, const size_t str_len, int
}
columns += col;
pen_x += cwidth * col;
pen_x += cwidth_fpx * col;
}
blf_batch_draw_end();
@ -425,11 +422,11 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
const char *str,
const size_t str_len,
struct ResultBLF *r_info,
int pen_y)
ft_pix pen_y)
{
GlyphBLF *g, *g_prev = NULL;
int pen_x = (int)font->pos[0];
int pen_y_basis = (int)font->pos[1] + pen_y;
ft_pix pen_x = ft_pix_from_int(font->pos[0]);
ft_pix pen_y_basis = ft_pix_from_int(font->pos[1]) + pen_y;
size_t i = 0;
/* buffer specific vars */
@ -449,18 +446,18 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
}
pen_x += blf_kerning(font, g_prev, g);
chx = pen_x + ((int)g->pos[0]);
chy = pen_y_basis + g->dims[1];
chx = ft_pix_to_int(pen_x + ft_pix_from_int(g->pos[0]));
chy = ft_pix_to_int(pen_y_basis + ft_pix_from_int(g->dims[1]));
if (g->pitch < 0) {
pen_y = pen_y_basis + (g->dims[1] - g->pos[1]);
pen_y = pen_y_basis + ft_pix_from_int(g->dims[1] - g->pos[1]);
}
else {
pen_y = pen_y_basis - (g->dims[1] - g->pos[1]);
pen_y = pen_y_basis - ft_pix_from_int(g->dims[1] - g->pos[1]);
}
if ((chx + g->dims[0]) >= 0 && chx < buf_info->dims[0] && (pen_y + g->dims[1]) >= 0 &&
pen_y < buf_info->dims[1]) {
if ((chx + g->dims[0]) >= 0 && chx < buf_info->dims[0] &&
(ft_pix_to_int(pen_y) + g->dims[1]) >= 0 && ft_pix_to_int(pen_y) < buf_info->dims[1]) {
/* don't draw beyond the buffer bounds */
int width_clip = g->dims[0];
int height_clip = g->dims[1];
@ -469,17 +466,20 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
if (width_clip + chx > buf_info->dims[0]) {
width_clip -= chx + width_clip - buf_info->dims[0];
}
if (height_clip + pen_y > buf_info->dims[1]) {
height_clip -= pen_y + height_clip - buf_info->dims[1];
if (height_clip + ft_pix_to_int(pen_y) > buf_info->dims[1]) {
height_clip -= ft_pix_to_int(pen_y) + height_clip - buf_info->dims[1];
}
/* drawing below the image? */
if (pen_y < 0) {
yb_start += (g->pitch < 0) ? -pen_y : pen_y;
height_clip += pen_y;
yb_start += (g->pitch < 0) ? -ft_pix_to_int(pen_y) : ft_pix_to_int(pen_y);
height_clip += ft_pix_to_int(pen_y);
pen_y = 0;
}
/* Avoid conversions in the pixel writing loop. */
const int pen_y_px = ft_pix_to_int(pen_y);
if (buf_info->fbuf) {
int yb = yb_start;
for (y = ((chy >= 0) ? 0 : -chy); y < height_clip; y++) {
@ -488,7 +488,7 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
if (a_byte) {
const float a = (a_byte / 255.0f) * b_col_float[3];
const size_t buf_ofs = (((size_t)(chx + x) +
((size_t)(pen_y + y) * (size_t)buf_info->dims[0])) *
((size_t)(pen_y_px + y) * (size_t)buf_info->dims[0])) *
(size_t)buf_info->ch);
float *fbuf = buf_info->fbuf + buf_ofs;
@ -519,7 +519,7 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
if (a_byte) {
const float a = (a_byte / 255.0f) * b_col_float[3];
const size_t buf_ofs = (((size_t)(chx + x) +
((size_t)(pen_y + y) * (size_t)buf_info->dims[0])) *
((size_t)(pen_y_px + y) * (size_t)buf_info->dims[0])) *
(size_t)buf_info->ch);
unsigned char *cbuf = buf_info->cbuf + buf_ofs;
@ -542,13 +542,13 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
}
}
pen_x += g->advance_i;
pen_x = ft_pix_round_advance(pen_x, g->advance_x);
g_prev = g;
}
if (r_info) {
r_info->lines = 1;
r_info->width = pen_x;
r_info->width = ft_pix_to_int(pen_x);
}
}
@ -573,23 +573,24 @@ void blf_font_draw_buffer(FontBLF *font,
* \{ */
static bool blf_font_width_to_strlen_glyph_process(
FontBLF *font, GlyphBLF *g_prev, GlyphBLF *g, int *pen_x, const int width_i)
FontBLF *font, GlyphBLF *g_prev, GlyphBLF *g, ft_pix *pen_x, const int width_i)
{
if (UNLIKELY(g == NULL)) {
return false; /* continue the calling loop. */
}
*pen_x += blf_kerning(font, g_prev, g);
*pen_x += g->advance_i;
*pen_x = ft_pix_round_advance(*pen_x, g->advance_x);
/* When true, break the calling loop. */
return (*pen_x >= width_i);
return (ft_pix_to_int(*pen_x) >= width_i);
}
size_t blf_font_width_to_strlen(
FontBLF *font, const char *str, const size_t str_len, float width, float *r_width)
FontBLF *font, const char *str, const size_t str_len, int width, int *r_width)
{
GlyphBLF *g, *g_prev;
int pen_x, width_new;
ft_pix pen_x;
ft_pix width_new;
size_t i, i_prev;
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
@ -605,7 +606,7 @@ size_t blf_font_width_to_strlen(
}
if (r_width) {
*r_width = (float)width_new;
*r_width = ft_pix_to_int(width_new);
}
blf_glyph_cache_release(font);
@ -613,15 +614,14 @@ size_t blf_font_width_to_strlen(
}
size_t blf_font_width_to_rstrlen(
FontBLF *font, const char *str, const size_t str_len, float width, float *r_width)
FontBLF *font, const char *str, const size_t str_len, int width, int *r_width)
{
GlyphBLF *g, *g_prev;
int pen_x, width_new;
ft_pix pen_x, width_new;
size_t i, i_prev, i_tmp;
const char *s, *s_prev;
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
const int width_i = (int)width;
i = BLI_strnlen(str, str_len);
s = BLI_str_find_prev_char_utf8(&str[i], str);
@ -642,13 +642,13 @@ size_t blf_font_width_to_rstrlen(
BLI_assert(i_tmp == i);
}
if (blf_font_width_to_strlen_glyph_process(font, g_prev, g, &pen_x, width_i)) {
if (blf_font_width_to_strlen_glyph_process(font, g_prev, g, &pen_x, width)) {
break;
}
}
if (r_width) {
*r_width = (float)width_new;
*r_width = ft_pix_to_int(width_new);
}
blf_glyph_cache_release(font);
@ -665,19 +665,18 @@ static void blf_font_boundbox_ex(FontBLF *font,
GlyphCacheBLF *gc,
const char *str,
const size_t str_len,
rctf *box,
rcti *box,
struct ResultBLF *r_info,
int pen_y)
ft_pix pen_y)
{
GlyphBLF *g, *g_prev = NULL;
int pen_x = 0;
ft_pix pen_x = 0;
size_t i = 0;
rctf gbox;
box->xmin = 32000.0f;
box->xmax = -32000.0f;
box->ymin = 32000.0f;
box->ymax = -32000.0f;
ft_pix box_xmin = ft_pix_from_int(32000);
ft_pix box_xmax = ft_pix_from_int(-32000);
ft_pix box_ymin = ft_pix_from_int(32000);
ft_pix box_ymax = ft_pix_from_int(-32000);
while ((i < str_len) && str[i]) {
g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i);
@ -686,44 +685,50 @@ static void blf_font_boundbox_ex(FontBLF *font,
continue;
}
pen_x += blf_kerning(font, g_prev, g);
const ft_pix pen_x_next = ft_pix_round_advance(pen_x, g->advance_x);
gbox.xmin = (float)pen_x;
gbox.xmax = (float)pen_x + g->advance;
gbox.ymin = g->box.ymin + (float)pen_y;
gbox.ymax = g->box.ymax + (float)pen_y;
const ft_pix gbox_xmin = pen_x;
const ft_pix gbox_xmax = pen_x_next;
const ft_pix gbox_ymin = g->box_ymin + pen_y;
const ft_pix gbox_ymax = g->box_ymax + pen_y;
if (gbox.xmin < box->xmin) {
box->xmin = gbox.xmin;
if (gbox_xmin < box_xmin) {
box_xmin = gbox_xmin;
}
if (gbox.ymin < box->ymin) {
box->ymin = gbox.ymin;
if (gbox_ymin < box_ymin) {
box_ymin = gbox_ymin;
}
if (gbox.xmax > box->xmax) {
box->xmax = gbox.xmax;
if (gbox_xmax > box_xmax) {
box_xmax = gbox_xmax;
}
if (gbox.ymax > box->ymax) {
box->ymax = gbox.ymax;
if (gbox_ymax > box_ymax) {
box_ymax = gbox_ymax;
}
pen_x += g->advance_i;
pen_x = pen_x_next;
g_prev = g;
}
if (box->xmin > box->xmax) {
box->xmin = 0.0f;
box->ymin = 0.0f;
box->xmax = 0.0f;
box->ymax = 0.0f;
if (box_xmin > box_xmax) {
box_xmin = 0;
box_ymin = 0;
box_xmax = 0;
box_ymax = 0;
}
box->xmin = ft_pix_to_int_floor(box_xmin);
box->xmax = ft_pix_to_int_ceil(box_xmax);
box->ymin = ft_pix_to_int_floor(box_ymin);
box->ymax = ft_pix_to_int_ceil(box_ymax);
if (r_info) {
r_info->lines = 1;
r_info->width = pen_x;
r_info->width = ft_pix_to_int(pen_x);
}
}
void blf_font_boundbox(
FontBLF *font, const char *str, const size_t str_len, rctf *r_box, struct ResultBLF *r_info)
FontBLF *font, const char *str, const size_t str_len, rcti *r_box, struct ResultBLF *r_info)
{
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
blf_font_boundbox_ex(font, gc, str, str_len, r_box, r_info, 0);
@ -738,7 +743,7 @@ void blf_font_width_and_height(FontBLF *font,
struct ResultBLF *r_info)
{
float xa, ya;
rctf box;
rcti box;
if (font->flags & BLF_ASPECT) {
xa = font->aspect[0];
@ -755,8 +760,8 @@ void blf_font_width_and_height(FontBLF *font,
else {
blf_font_boundbox(font, str, str_len, &box, r_info);
}
*r_width = (BLI_rctf_size_x(&box) * xa);
*r_height = (BLI_rctf_size_y(&box) * ya);
*r_width = ((float)BLI_rcti_size_x(&box) * xa);
*r_height = ((float)BLI_rcti_size_y(&box) * ya);
}
float blf_font_width(FontBLF *font,
@ -765,7 +770,7 @@ float blf_font_width(FontBLF *font,
struct ResultBLF *r_info)
{
float xa;
rctf box;
rcti box;
if (font->flags & BLF_ASPECT) {
xa = font->aspect[0];
@ -780,7 +785,7 @@ float blf_font_width(FontBLF *font,
else {
blf_font_boundbox(font, str, str_len, &box, r_info);
}
return BLI_rctf_size_x(&box) * xa;
return (float)BLI_rcti_size_x(&box) * xa;
}
float blf_font_height(FontBLF *font,
@ -789,7 +794,7 @@ float blf_font_height(FontBLF *font,
struct ResultBLF *r_info)
{
float ya;
rctf box;
rcti box;
if (font->flags & BLF_ASPECT) {
ya = font->aspect[1];
@ -804,7 +809,7 @@ float blf_font_height(FontBLF *font,
else {
blf_font_boundbox(font, str, str_len, &box, r_info);
}
return BLI_rctf_size_y(&box) * ya;
return (float)BLI_rcti_size_y(&box) * ya;
}
float blf_font_fixed_width(FontBLF *font)
@ -822,12 +827,12 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font,
BLF_GlyphBoundsFn user_fn,
void *user_data,
struct ResultBLF *r_info,
int pen_y)
ft_pix pen_y)
{
GlyphBLF *g, *g_prev = NULL;
int pen_x = 0;
ft_pix pen_x = 0;
size_t i = 0, i_curr;
rcti gbox;
rcti gbox_px;
if (str_len == 0) {
/* early output. */
@ -842,15 +847,23 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font,
continue;
}
pen_x += blf_kerning(font, g_prev, g);
const ft_pix pen_x_next = ft_pix_round_advance(pen_x, g->advance_x);
gbox.xmin = pen_x;
gbox.xmax = gbox.xmin + MIN2(g->advance_i, g->dims[0]);
gbox.ymin = pen_y;
gbox.ymax = gbox.ymin - g->dims[1];
gbox_px.xmin = ft_pix_to_int_floor(pen_x);
gbox_px.xmax = ft_pix_to_int_ceil(pen_x_next);
gbox_px.ymin = ft_pix_to_int_floor(pen_y);
gbox_px.ymax = gbox_px.ymin - g->dims[1];
const int advance_x_px = gbox_px.xmax - gbox_px.xmin;
pen_x += g->advance_i;
pen_x = pen_x_next;
if (user_fn(str, i_curr, &gbox, g->advance_i, &g->box, g->pos, user_data) == false) {
rcti box_px;
box_px.xmin = ft_pix_to_int_floor(g->box_xmin);
box_px.xmax = ft_pix_to_int_ceil(g->box_xmax);
box_px.ymin = ft_pix_to_int_floor(g->box_ymin);
box_px.ymax = ft_pix_to_int_ceil(g->box_ymax);
if (user_fn(str, i_curr, &gbox_px, advance_x_px, &box_px, g->pos, user_data) == false) {
break;
}
@ -859,7 +872,7 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font,
if (r_info) {
r_info->lines = 1;
r_info->width = pen_x;
r_info->width = ft_pix_to_int(pen_x);
}
}
void blf_font_boundbox_foreach_glyph(FontBLF *font,
@ -897,22 +910,26 @@ static void blf_font_wrap_apply(FontBLF *font,
GlyphCacheBLF *gc,
const char *str,
const size_t str_len,
int pen_y,
ft_pix pen_y,
void *userdata),
void *userdata)
{
GlyphBLF *g, *g_prev = NULL;
int pen_x = 0, pen_y = 0;
ft_pix pen_x = 0;
ft_pix pen_y = 0;
size_t i = 0;
int lines = 0;
int pen_x_next = 0;
ft_pix pen_x_next = 0;
/* Space between lines needs to be aligned to the pixel grid (T97310). */
ft_pix line_height = FT_PIX_FLOOR(blf_font_height_max_ft_pix(font));
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
struct WordWrapVars {
int wrap_width;
ft_pix wrap_width;
size_t start, last[2];
} wrap = {font->wrap_width != -1 ? font->wrap_width : INT_MAX, 0, {0, 0}};
} wrap = {font->wrap_width != -1 ? ft_pix_from_int(font->wrap_width) : INT_MAX, 0, {0, 0}};
// printf("%s wrapping (%d, %d) `%s`:\n", __func__, str_len, strlen(str), str);
while ((i < str_len) && str[i]) {
@ -936,7 +953,7 @@ static void blf_font_wrap_apply(FontBLF *font,
*
* This is _only_ done when we know for sure the character is ascii (newline or a space).
*/
pen_x_next = pen_x + g->advance_i;
pen_x_next = ft_pix_round_advance(pen_x, g->advance_x);
if (UNLIKELY((pen_x_next >= wrap.wrap_width) && (wrap.start != wrap.last[0]))) {
do_draw = true;
}
@ -964,7 +981,7 @@ static void blf_font_wrap_apply(FontBLF *font,
wrap.start = wrap.last[0];
i = wrap.last[1];
pen_x = 0;
pen_y -= blf_font_height_max(font);
pen_y -= line_height;
g_prev = NULL;
lines += 1;
continue;
@ -979,7 +996,7 @@ static void blf_font_wrap_apply(FontBLF *font,
if (r_info) {
r_info->lines = lines;
/* width of last line only (with wrapped lines) */
r_info->width = pen_x_next;
r_info->width = ft_pix_to_int(pen_x_next);
}
blf_glyph_cache_release(font);
@ -990,7 +1007,7 @@ static void blf_font_draw__wrap_cb(FontBLF *font,
GlyphCacheBLF *gc,
const char *str,
const size_t str_len,
int pen_y,
ft_pix pen_y,
void *UNUSED(userdata))
{
blf_font_draw_ex(font, gc, str, str_len, NULL, pen_y);
@ -1008,22 +1025,22 @@ static void blf_font_boundbox_wrap_cb(FontBLF *font,
GlyphCacheBLF *gc,
const char *str,
const size_t str_len,
int pen_y,
ft_pix pen_y,
void *userdata)
{
rctf *box = userdata;
rctf box_single;
rcti *box = userdata;
rcti box_single;
blf_font_boundbox_ex(font, gc, str, str_len, &box_single, NULL, pen_y);
BLI_rctf_union(box, &box_single);
BLI_rcti_union(box, &box_single);
}
void blf_font_boundbox__wrap(
FontBLF *font, const char *str, const size_t str_len, rctf *box, struct ResultBLF *r_info)
FontBLF *font, const char *str, const size_t str_len, rcti *box, struct ResultBLF *r_info)
{
box->xmin = 32000.0f;
box->xmax = -32000.0f;
box->ymin = 32000.0f;
box->ymax = -32000.0f;
box->xmin = 32000;
box->xmax = -32000;
box->ymin = 32000;
box->ymax = -32000;
blf_font_wrap_apply(font, str, str_len, r_info, blf_font_boundbox_wrap_cb, box);
}
@ -1033,7 +1050,7 @@ static void blf_font_draw_buffer__wrap_cb(FontBLF *font,
GlyphCacheBLF *gc,
const char *str,
const size_t str_len,
int pen_y,
ft_pix pen_y,
void *UNUSED(userdata))
{
blf_font_draw_buffer_ex(font, gc, str, str_len, NULL, pen_y);
@ -1084,44 +1101,56 @@ int blf_font_count_missing_chars(FontBLF *font,
/** \name Font Query: Attributes
* \{ */
int blf_font_height_max(FontBLF *font)
static ft_pix blf_font_height_max_ft_pix(FontBLF *font)
{
int height_max;
if (FT_IS_SCALABLE(font->face)) {
height_max = (int)((float)(font->face->ascender - font->face->descender) *
(((float)font->face->size->metrics.y_ppem) /
((float)font->face->units_per_EM)));
ft_pix height_max;
FT_Face face = font->face;
if (FT_IS_SCALABLE(face)) {
height_max = ft_pix_from_int((int)(face->ascender - face->descender) *
(int)face->size->metrics.y_ppem) /
(ft_pix)face->units_per_EM;
}
else {
height_max = (int)(((float)font->face->size->metrics.height) / 64.0f);
height_max = (ft_pix)face->size->metrics.height;
}
/* can happen with size 1 fonts */
return MAX2(height_max, 1);
return MAX2(height_max, ft_pix_from_int(1));
}
int blf_font_height_max(FontBLF *font)
{
return ft_pix_to_int(blf_font_height_max_ft_pix(font));
}
static ft_pix blf_font_width_max_ft_pix(FontBLF *font)
{
ft_pix width_max;
const FT_Face face = font->face;
if (FT_IS_SCALABLE(face)) {
width_max = ft_pix_from_int((int)(face->bbox.xMax - face->bbox.xMin) *
(int)face->size->metrics.x_ppem) /
(ft_pix)face->units_per_EM;
}
else {
width_max = (ft_pix)face->size->metrics.max_advance;
}
/* can happen with size 1 fonts */
return MAX2(width_max, ft_pix_from_int(1));
}
int blf_font_width_max(FontBLF *font)
{
int width_max;
if (FT_IS_SCALABLE(font->face)) {
width_max = (int)((float)(font->face->bbox.xMax - font->face->bbox.xMin) *
(((float)font->face->size->metrics.x_ppem) /
((float)font->face->units_per_EM)));
}
else {
width_max = (int)(((float)font->face->size->metrics.max_advance) / 64.0f);
}
/* can happen with size 1 fonts */
return MAX2(width_max, 1);
return ft_pix_to_int(blf_font_width_max_ft_pix(font));
}
float blf_font_descender(FontBLF *font)
int blf_font_descender(FontBLF *font)
{
return ((float)font->face->size->metrics.descender) / 64.0f;
return ft_pix_to_int((ft_pix)font->face->size->metrics.descender);
}
float blf_font_ascender(FontBLF *font)
int blf_font_ascender(FontBLF *font)
{
return ((float)font->face->size->metrics.ascender) / 64.0f;
return ft_pix_to_int((ft_pix)font->face->size->metrics.ascender);
}
char *blf_display_name(FontBLF *font)
@ -1170,8 +1199,8 @@ static void blf_font_fill(FontBLF *font)
font->aspect[0] = 1.0f;
font->aspect[1] = 1.0f;
font->aspect[2] = 1.0f;
font->pos[0] = 0.0f;
font->pos[1] = 0.0f;
font->pos[0] = 0;
font->pos[1] = 0;
font->angle = 0.0f;
for (int i = 0; i < 16; i++) {
@ -1184,10 +1213,10 @@ static void blf_font_fill(FontBLF *font)
font->color[2] = 0;
font->color[3] = 255;
font->clip_rec.xmin = 0.0f;
font->clip_rec.xmax = 0.0f;
font->clip_rec.ymin = 0.0f;
font->clip_rec.ymax = 0.0f;
font->clip_rec.xmin = 0;
font->clip_rec.xmax = 0;
font->clip_rec.ymin = 0;
font->clip_rec.ymax = 0;
font->flags = 0;
font->dpi = 0;
font->size = 0;

View File

@ -183,8 +183,7 @@ static GlyphBLF *blf_glyph_cache_add_glyph(
GlyphBLF *g = (GlyphBLF *)MEM_callocN(sizeof(GlyphBLF), "blf_glyph_get");
g->c = charcode;
g->idx = glyph_index;
g->advance = ((float)glyph->advance.x) / 64.0f;
g->advance_i = (int)g->advance;
g->advance_x = (ft_pix)glyph->advance.x;
g->pos[0] = glyph->bitmap_left;
g->pos[1] = glyph->bitmap_top;
g->dims[0] = (int)glyph->bitmap.width;
@ -193,10 +192,14 @@ static GlyphBLF *blf_glyph_cache_add_glyph(
FT_BBox bbox;
FT_Outline_Get_CBox(&(glyph->outline), &bbox);
g->box.xmin = ((float)bbox.xMin) / 64.0f;
g->box.xmax = ((float)bbox.xMax) / 64.0f;
g->box.ymin = ((float)bbox.yMin) / 64.0f;
g->box.ymax = ((float)bbox.yMax) / 64.0f;
g->box_xmin = (ft_pix)bbox.xMin;
g->box_xmax = (ft_pix)bbox.xMax;
g->box_ymin = (ft_pix)bbox.yMin;
g->box_ymax = (ft_pix)bbox.yMax;
/* Used to improve advance when hinting is enabled. */
g->lsb_delta = (ft_pix)glyph->lsb_delta;
g->rsb_delta = (ft_pix)glyph->rsb_delta;
const int buffer_size = (int)(glyph->bitmap.width * glyph->bitmap.rows);
if (buffer_size != 0) {
@ -488,28 +491,29 @@ void blf_glyph_free(GlyphBLF *g)
/** \name Glyph Bounds Calculation
* \{ */
static void blf_glyph_calc_rect(rctf *rect, GlyphBLF *g, float x, float y)
static void blf_glyph_calc_rect(rcti *rect, GlyphBLF *g, const int x, const int y)
{
rect->xmin = floorf(x + (float)g->pos[0]);
rect->xmax = rect->xmin + (float)g->dims[0];
rect->ymin = floorf(y + (float)g->pos[1]);
rect->ymax = rect->ymin - (float)g->dims[1];
rect->xmin = x + g->pos[0];
rect->xmax = rect->xmin + g->dims[0];
rect->ymin = y + g->pos[1];
rect->ymax = rect->ymin - g->dims[1];
}
static void blf_glyph_calc_rect_test(rctf *rect, GlyphBLF *g, float x, float y)
static void blf_glyph_calc_rect_test(rcti *rect, GlyphBLF *g, const int x, const int y)
{
/* Intentionally check with `g->advance`, because this is the
* width used by BLF_width. This allows that the text slightly
* overlaps the clipping border to achieve better alignment. */
rect->xmin = floorf(x);
rect->xmax = rect->xmin + MIN2(g->advance, (float)g->dims[0]);
rect->ymin = floorf(y);
rect->ymax = rect->ymin - (float)g->dims[1];
rect->xmin = x;
rect->xmax = rect->xmin + MIN2(ft_pix_to_int(g->advance_x), g->dims[0]);
rect->ymin = y;
rect->ymax = rect->ymin - g->dims[1];
}
static void blf_glyph_calc_rect_shadow(rctf *rect, GlyphBLF *g, float x, float y, FontBLF *font)
static void blf_glyph_calc_rect_shadow(
rcti *rect, GlyphBLF *g, const int x, const int y, FontBLF *font)
{
blf_glyph_calc_rect(rect, g, x + (float)font->shadow_x, y + (float)font->shadow_y);
blf_glyph_calc_rect(rect, g, x + font->shadow_x, y + font->shadow_y);
}
/** \} */
@ -521,18 +525,18 @@ static void blf_glyph_calc_rect_shadow(rctf *rect, GlyphBLF *g, float x, float y
static void blf_texture_draw(const unsigned char color[4],
const int glyph_size[2],
const int offset,
float x1,
float y1,
float x2,
float y2)
const int x1,
const int y1,
const int x2,
const int y2)
{
/* Only one vertex per glyph, geometry shader expand it into a quad. */
/* TODO: Get rid of Geom Shader because it's not optimal AT ALL for the GPU. */
copy_v4_fl4(GPU_vertbuf_raw_step(&g_batch.pos_step),
x1 + g_batch.ofs[0],
y1 + g_batch.ofs[1],
x2 + g_batch.ofs[0],
y2 + g_batch.ofs[1]);
(float)(x1 + g_batch.ofs[0]),
(float)(y1 + g_batch.ofs[1]),
(float)(x2 + g_batch.ofs[0]),
(float)(y2 + g_batch.ofs[1]));
copy_v4_v4_uchar(GPU_vertbuf_raw_step(&g_batch.col_step), color);
copy_v2_v2_int(GPU_vertbuf_raw_step(&g_batch.glyph_size_step), glyph_size);
*((int *)GPU_vertbuf_raw_step(&g_batch.offset_step)) = offset;
@ -547,10 +551,10 @@ static void blf_texture_draw(const unsigned char color[4],
static void blf_texture5_draw(const unsigned char color_in[4],
const int glyph_size[2],
const int offset,
float x1,
float y1,
float x2,
float y2)
const int x1,
const int y1,
const int x2,
const int y2)
{
int glyph_size_flag[2];
/* flag the x and y component signs for 5x5 blurring */
@ -563,10 +567,10 @@ static void blf_texture5_draw(const unsigned char color_in[4],
static void blf_texture3_draw(const unsigned char color_in[4],
const int glyph_size[2],
const int offset,
float x1,
float y1,
float x2,
float y2)
const int x1,
const int y1,
const int x2,
const int y2)
{
int glyph_size_flag[2];
/* flag the x component sign for 3x3 blurring */
@ -576,7 +580,7 @@ static void blf_texture3_draw(const unsigned char color_in[4],
blf_texture_draw(color_in, glyph_size_flag, offset, x1, y1, x2, y2);
}
void blf_glyph_draw(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, float y)
void blf_glyph_draw(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, const int x, const int y)
{
if ((!g->dims[0]) || (!g->dims[1])) {
return;
@ -615,11 +619,11 @@ void blf_glyph_draw(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, floa
}
if (font->flags & BLF_CLIPPING) {
rctf rect_test;
rcti rect_test;
blf_glyph_calc_rect_test(&rect_test, g, x, y);
BLI_rctf_translate(&rect_test, font->pos[0], font->pos[1]);
BLI_rcti_translate(&rect_test, font->pos[0], font->pos[1]);
if (!BLI_rctf_inside_rctf(&font->clip_rec, &rect_test)) {
if (!BLI_rcti_inside_rcti(&font->clip_rec, &rect_test)) {
return;
}
}
@ -630,7 +634,7 @@ void blf_glyph_draw(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, floa
}
if (font->flags & BLF_SHADOW) {
rctf rect_ofs;
rcti rect_ofs;
blf_glyph_calc_rect_shadow(&rect_ofs, g, x, y, font);
if (font->shadow == 0) {
@ -662,7 +666,7 @@ void blf_glyph_draw(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, floa
}
}
rctf rect;
rcti rect;
blf_glyph_calc_rect(&rect, g, x, y);
#if BLF_BLUR_ENABLE

View File

@ -67,18 +67,18 @@ void blf_font_draw_buffer__wrap(struct FontBLF *font,
size_t str_len,
struct ResultBLF *r_info);
size_t blf_font_width_to_strlen(
struct FontBLF *font, const char *str, size_t str_len, float width, float *r_width);
struct FontBLF *font, const char *str, size_t str_len, int width, int *r_width);
size_t blf_font_width_to_rstrlen(
struct FontBLF *font, const char *str, size_t str_len, float width, float *r_width);
struct FontBLF *font, const char *str, size_t str_len, int width, int *r_width);
void blf_font_boundbox(struct FontBLF *font,
const char *str,
size_t str_len,
struct rctf *r_box,
struct rcti *r_box,
struct ResultBLF *r_info);
void blf_font_boundbox__wrap(struct FontBLF *font,
const char *str,
size_t str_len,
struct rctf *r_box,
struct rcti *r_box,
struct ResultBLF *r_info);
void blf_font_width_and_height(struct FontBLF *font,
const char *str,
@ -97,8 +97,8 @@ float blf_font_height(struct FontBLF *font,
float blf_font_fixed_width(struct FontBLF *font);
int blf_font_height_max(struct FontBLF *font);
int blf_font_width_max(struct FontBLF *font);
float blf_font_descender(struct FontBLF *font);
float blf_font_ascender(struct FontBLF *font);
int blf_font_descender(struct FontBLF *font);
int blf_font_ascender(struct FontBLF *font);
char *blf_display_name(struct FontBLF *font);
@ -109,7 +109,7 @@ void blf_font_boundbox_foreach_glyph(struct FontBLF *font,
size_t str_step_ofs,
const struct rcti *glyph_step_bounds,
int glyph_advance_x,
const struct rctf *glyph_bounds,
const struct rcti *glyph_bounds,
const int glyph_bearing[2],
void *user_data),
void *user_data,
@ -133,7 +133,7 @@ struct GlyphBLF *blf_glyph_ensure(struct FontBLF *font, struct GlyphCacheBLF *gc
void blf_glyph_free(struct GlyphBLF *g);
void blf_glyph_draw(
struct FontBLF *font, struct GlyphCacheBLF *gc, struct GlyphBLF *g, float x, float y);
struct FontBLF *font, struct GlyphCacheBLF *gc, struct GlyphBLF *g, int x, int y);
#ifdef WIN32
/* blf_font_win32_compat.c */

View File

@ -10,6 +10,78 @@
#include "GPU_texture.h"
#include "GPU_vertex_buffer.h"
/* -------------------------------------------------------------------- */
/** \name Sub-Pixel Offset & Utilities
*
* Free-type uses fixed point precision for sub-pixel offsets.
* Utility functions here avoid exposing the details in the BLF API.
* \{ */
/**
* This is an internal type that represents sub-pixel positioning,
* users of this type are to use `ft_pix_*` functions to keep scaling/rounding in one place.
*/
typedef int32_t ft_pix;
/* Macros copied from `include/freetype/internal/ftobjs.h`. */
/* FIXME(@campbellbarton): Follow rounding from Blender 3.1x and older.
* This is what users will expect and changing this creates wider spaced text.
* Use this macro to communicate that rounding should be used, using floor is to avoid
* user visible changes, which can be reviewed and handled separately. */
#define USE_LEGACY_SPACING
#define FT_PIX_FLOOR(x) ((x) & ~63)
#define FT_PIX_ROUND(x) FT_PIX_FLOOR((x) + 32)
#define FT_PIX_CEIL(x) ((x) + 63)
#ifdef USE_LEGACY_SPACING
# define FT_PIX_DEFAULT_ROUNDING(x) FT_PIX_FLOOR(x)
#else
# define FT_PIX_DEFAULT_ROUNDING(x) FT_PIX_ROUND(x)
#endif
BLI_INLINE int ft_pix_to_int(ft_pix v)
{
#ifdef USE_LEGACY_SPACING
return (int)(v >> 6);
#else
return (int)(FT_PIX_DEFAULT_ROUNDING(v) >> 6);
#endif
}
BLI_INLINE int ft_pix_to_int_floor(ft_pix v)
{
return (int)(v >> 6); /* No need for explicit floor as the bits are removed when shifting. */
}
BLI_INLINE int ft_pix_to_int_ceil(ft_pix v)
{
return (int)(FT_PIX_CEIL(v) >> 6);
}
BLI_INLINE ft_pix ft_pix_from_int(int v)
{
return v * 64;
}
BLI_INLINE ft_pix ft_pix_from_float(float v)
{
return lroundf(v * 64.0f);
}
BLI_INLINE ft_pix ft_pix_round_advance(ft_pix v, ft_pix step)
{
/* See #USE_LEGACY_SPACING, rounding logic could change here. */
return FT_PIX_DEFAULT_ROUNDING(v) + FT_PIX_DEFAULT_ROUNDING(step);
}
#undef FT_PIX_ROUND
#undef FT_PIX_CEIL
#undef FT_PIX_DEFAULT_ROUNDING
/** \} */
#define BLF_BATCH_DRAW_LEN_MAX 2048 /* in glyph */
/* Number of characters in GlyphCacheBLF.glyph_ascii_table. */
@ -28,7 +100,7 @@ typedef struct BatchBLF {
struct GPUVertBufRaw pos_step, col_step, offset_step, glyph_size_step;
unsigned int pos_loc, col_loc, offset_loc, glyph_size_loc;
unsigned int glyph_len;
float ofs[2]; /* copy of font->pos */
int ofs[2]; /* copy of font->pos */
float mat[4][4]; /* previous call modelmatrix. */
bool enabled, active, simple_shader;
struct GlyphCacheBLF *glyph_cache;
@ -86,12 +158,16 @@ typedef struct GlyphBLF {
FT_UInt idx;
/* glyph box. */
rctf box;
ft_pix box_xmin;
ft_pix box_xmax;
ft_pix box_ymin;
ft_pix box_ymax;
/* advance size. */
float advance;
/* avoid conversion to int while drawing */
int advance_i;
ft_pix advance_x;
/* The difference in bearings when hinting is active, zero otherwise. */
ft_pix lsb_delta;
ft_pix rsb_delta;
/* position inside the texture where this glyph is store. */
int offset;
@ -154,7 +230,7 @@ typedef struct FontBLF {
float aspect[3];
/* initial position for draw the text. */
float pos[3];
int pos[3];
/* angle in radians. */
float angle;
@ -183,7 +259,7 @@ typedef struct FontBLF {
float m[16];
/* clipping rectangle. */
rctf clip_rec;
rcti clip_rec;
/* the width to wrap the text, see BLF_WORD_WRAP */
int wrap_width;

View File

@ -64,7 +64,7 @@ void BLF_thumb_preview(const char *filepath,
/* Always create the image with a white font,
* the caller can theme how it likes */
memcpy(font->buf_info.col_init, font_color, sizeof(font->buf_info.col_init));
font->pos[1] = (float)h;
font->pos[1] = h;
font_size_curr = font_size;
@ -84,7 +84,7 @@ void BLF_thumb_preview(const char *filepath,
font_size_curr -= (font_size_curr / font_shrink);
font_shrink += 1;
font->pos[1] -= blf_font_ascender(font) * 1.1f;
font->pos[1] -= (int)((float)blf_font_ascender(font) * 1.1f);
/* We fallback to default english strings in case not enough chars are available in current
* font for given translated string (useful in non-latin i18n context, like Chinese,

View File

@ -7,6 +7,7 @@
* \ingroup bke
*/
#include "BLI_bitmap.h"
#include "BLI_sys_types.h" /* for bool */
#ifdef __cplusplus
@ -258,16 +259,20 @@ struct NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(
* \param count: Number of values in the array.
* \param index: Index of the element about to be updated, or -1.
* \param[out] r_force_all: Set to true if all channels must be inserted. May be NULL.
* \return False if correction fails due to a division by zero,
* or null r_force_all when all channels are required.
* \param[out] r_successful_remaps: Bits will be enabled for indices that are both intended to be
* remapped and succeeded remapping. With both, it allows caller to check successfully remapped
* indices without having to explicitly check whether the index was intended to be remapped.
*/
bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
void BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
struct PointerRNA *prop_ptr,
struct PropertyRNA *prop,
float *values,
int count,
int index,
bool *r_force_all);
const struct AnimationEvalContext *anim_eval_context,
bool *r_force_all,
BLI_bitmap *r_successful_remaps);
/**
* Free all cached contexts from the list.
*/

View File

@ -165,7 +165,7 @@ void BKE_pchan_minmax(const struct Object *ob,
float r_max[3]);
/**
* Calculate the axis aligned bounds of the pose of `ob` in world-space.
*
* `r_min` and `r_max` are expanded to fit `ob->pose` so the caller must initialize them
* (typically using #INIT_MINMAX).
*

View File

@ -64,7 +64,7 @@ struct CustomDataLayer *BKE_id_attribute_find(const struct ID *id,
int type,
AttributeDomain domain);
AttributeDomain BKE_id_attribute_domain(struct ID *id, const struct CustomDataLayer *layer);
AttributeDomain BKE_id_attribute_domain(const struct ID *id, const struct CustomDataLayer *layer);
int BKE_id_attribute_data_length(struct ID *id, struct CustomDataLayer *layer);
bool BKE_id_attribute_required(struct ID *id, struct CustomDataLayer *layer);
bool BKE_id_attribute_rename(struct ID *id,

View File

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

View File

@ -16,7 +16,7 @@ struct Main;
struct PointerRNA;
/**
Callbacks for One Off Actions
* Callbacks for One Off Actions
* =============================
*
* - `{ACTION}` use in cases where only a single callback is required,

View File

@ -59,7 +59,7 @@ struct CryptomatteHash {
std::string hex_encoded() const;
/**
Convert a cryptomatte hash to a float.
* Convert a cryptomatte hash to a float.
*
* Cryptomatte hashes are stored in float textures and images. The conversion is taken from the
* cryptomatte specification. See Floating point conversion section in

View File

@ -76,6 +76,11 @@ class CurvesGeometryRuntime {
mutable Vector<float3> evaluated_position_cache;
mutable std::mutex position_cache_mutex;
mutable bool position_cache_dirty = true;
/**
* The evaluated positions result, using a separate span in case all curves are poly curves,
* in which case a separate array of evaluated positions is unnecessary.
*/
mutable Span<float3> evaluated_positions_span;
/**
* Cache of lengths along each evaluated curve for for each evaluated point. If a curve is
@ -158,6 +163,9 @@ class CurvesGeometry : public ::CurvesGeometry {
/** Return the number of curves with each type. */
std::array<int, CURVE_TYPES_NUM> count_curve_types() const;
/** Return true if all of the curves have the provided type. */
bool is_single_type(CurveType type) const;
Span<float3> positions() const;
MutableSpan<float3> positions_for_write();
@ -174,6 +182,13 @@ class CurvesGeometry : public ::CurvesGeometry {
/** Mutable access to curve resolution. Call #tag_topology_changed after changes. */
MutableSpan<int> resolution_for_write();
/**
* Which method to use for calculating the normals of evaluated points (#NormalMode).
* Call #tag_normals_changed after changes.
*/
VArray<int8_t> normal_mode() const;
MutableSpan<int8_t> normal_mode_for_write();
/**
* Handle types for Bezier control points. Call #tag_topology_changed after changes.
*/
@ -280,6 +295,8 @@ class CurvesGeometry : public ::CurvesGeometry {
Span<int> bezier_evaluated_offsets_for_curve(int curve_index) const;
Span<float3> evaluated_positions() const;
Span<float3> evaluated_tangents() const;
Span<float3> evaluated_normals() const;
/**
* Return a cache of accumulated lengths along the curve. Each item is the length of the
@ -365,6 +382,7 @@ namespace curves {
*/
inline int curve_segment_size(const int points_num, const bool cyclic)
{
BLI_assert(points_num > 0);
return cyclic ? points_num : points_num - 1;
}
@ -379,6 +397,31 @@ inline float3 decode_surface_bary_coord(const float2 &v)
return {v.x, v.y, 1.0f - v.x - v.y};
}
namespace poly {
/**
* Calculate the direction at every point, defined as the normalized average of the two neighboring
* segments (and if non-cyclic, the direction of the first and last segments). This is different
* than evaluating the derivative of the basis functions for curve types like NURBS, Bezier, or
* Catmull Rom, though the results may be similar.
*/
void calculate_tangents(Span<float3> positions, bool is_cyclic, MutableSpan<float3> tangents);
/**
* Calculate directions perpendicular to the tangent at every point by rotating an arbitrary
* starting vector by the same rotation of each tangent. If the curve is cylic, propagate a
* correction through the entire to make sure the first and last normal align.
*/
void calculate_normals_minimum(Span<float3> tangents, bool cyclic, MutableSpan<float3> normals);
/**
* Calculate a vector perpendicular to every tangent on the X-Y plane (unless the tangent is
* vertical, in that case use the X direction).
*/
void calculate_normals_z_up(Span<float3> tangents, MutableSpan<float3> normals);
} // namespace poly
namespace bezier {
/**
@ -586,6 +629,11 @@ inline IndexRange CurvesGeometry::curves_range() const
return IndexRange(this->curves_num());
}
inline bool CurvesGeometry::is_single_type(const CurveType type) const
{
return this->count_curve_types()[type] == this->curves_num();
}
inline IndexRange CurvesGeometry::points_for_curve(const int index) const
{
/* Offsets are not allocated when there are no curves. */
@ -639,8 +687,7 @@ inline IndexRange CurvesGeometry::lengths_range_for_curve(const int curve_index,
BLI_assert(cyclic == this->cyclic()[curve_index]);
const IndexRange points = this->evaluated_points_for_curve(curve_index);
const int start = points.start() + curve_index;
const int size = curves::curve_segment_size(points.size(), cyclic);
return {start, size};
return {start, points.is_empty() ? 0 : curves::curve_segment_size(points.size(), cyclic)};
}
inline Span<float> CurvesGeometry::evaluated_lengths_for_curve(const int curve_index,

View File

@ -43,16 +43,16 @@ typedef struct CfraElem {
/* ************** F-Curve Modifiers *************** */
/* F-Curve Modifier Type-Info (fmi):
* This struct provides function pointers for runtime, so that functions can be
* written more generally (with fewer/no special exceptions for various modifiers).
/**
* F-Curve Modifier Type-Info (fmi):
* This struct provides function pointers for runtime, so that functions can be
* written more generally (with fewer/no special exceptions for various modifiers).
*
* Callers of these functions must check that they actually point to something useful,
* as some constraints don't define some of these.
* Callers of these functions must check that they actually point to something useful,
* as some constraints don't define some of these.
*
* Warning: it is not too advisable to reorder order of members of this struct,
* as you'll have to edit quite a few ($FMODIFIER_NUM_TYPES) of these
* structs.
* \warning it is not too advisable to reorder order of members of this struct,
* as you'll have to edit quite a few (#FMODIFIER_NUM_TYPES) of these structs.
*/
typedef struct FModifierTypeInfo {
/* admin/ident */

View File

@ -31,16 +31,17 @@ typedef enum eGPUpdateCacheNodeFlag {
} eGPUpdateCacheNodeFlag;
/**
* Cache for what needs to be updated after bGPdata was modified.
* Cache for what needs to be updated after bGPdata was modified.
*
* Every node holds information about one element that was changed:
* - the index of where that element is in the linked-list
* - the pointer to the original element in bGPdata
* Additionally, nodes also hold other nodes that are one "level" below them.
* E.g. a node that represents a change on a bGPDframe could contain a set of
* nodes that represent a change on bGPDstrokes.
* These nodes are stored in a red-black tree so that they are sorted by their
* index to make sure they can be processed in the correct order.
* Every node holds information about one element that was changed:
* - The index of where that element is in the linked-list.
* - The pointer to the original element in bGPdata.
*
* Additionally, nodes also hold other nodes that are one "level" below them.
* E.g. a node that represents a change on a bGPDframe could contain a set of
* nodes that represent a change on bGPDstrokes.
* These nodes are stored in a red-black tree so that they are sorted by their
* index to make sure they can be processed in the correct order.
*/
typedef struct GPencilUpdateCache {
/* Mapping from index to a GPencilUpdateCache struct. */

View File

@ -329,7 +329,7 @@ void BKE_image_merge(struct Main *bmain, struct Image *dest, struct Image *sourc
bool BKE_image_scale(struct Image *image, int width, int height);
/**
* Check if texture has alpha (planes == 32 || planes == 16).
* Check if texture has alpha `planes == 32 || planes == 16`.
*/
bool BKE_image_has_alpha(struct Image *image);
@ -350,13 +350,13 @@ void BKE_image_get_tile_label(struct Image *ima,
* Checks whether the given filepath refers to a UDIM tiled texture.
* If yes, the range from the lowest to the highest tile is returned.
*
* `filepath` may be modified to ensure a UDIM token is present.
* `tiles` may be filled even if the result ultimately is false!
* \param filepath: may be modified to ensure a UDIM token is present.
* \param tiles: may be filled even if the result ultimately is false!
*/
bool BKE_image_get_tile_info(char *filepath,
struct ListBase *tiles,
int *tile_start,
int *tile_range);
int *r_tile_start,
int *r_tile_range);
struct ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *label);
bool BKE_image_remove_tile(struct Image *ima, struct ImageTile *tile);
@ -385,7 +385,7 @@ typedef enum {
void BKE_image_ensure_tile_token(char *filename);
/**
* When provided with an absolute virtual filepath, check to see if at least
* When provided with an absolute virtual `filepath`, check to see if at least
* one concrete file exists.
* Note: This function requires directory traversal and may be inefficient in time-critical,
* or iterative, code paths.
@ -394,8 +394,8 @@ bool BKE_image_tile_filepath_exists(const char *filepath);
/**
* Retrieves the UDIM token format and returns the pattern from the provided `filepath`.
* The returned pattern is typically passed to either `BKE_image_get_tile_number_from_filepath` or
* `BKE_image_set_filepath_from_tile_number`.
* The returned pattern is typically passed to either #BKE_image_get_tile_number_from_filepath or
* #BKE_image_set_filepath_from_tile_number.
*/
char *BKE_image_get_tile_strformat(const char *filepath, eUDIM_TILE_FORMAT *r_tile_format);
bool BKE_image_get_tile_number_from_filepath(const char *filepath,

View File

@ -28,7 +28,7 @@ void BKE_mesh_calc_loop_tangent_single_ex(const struct MVert *mverts,
int numPolys,
struct ReportList *reports);
/**
* Wrapper around BKE_mesh_calc_loop_tangent_single_ex, which takes care of most boiling code.
* Wrapper around BKE_mesh_calc_loop_tangent_single_ex, which takes care of most boilerplate code.
* \note
* - There must be a valid loop's CD_NORMALS available.
* - The mesh should be made of only tris and quads!

View File

@ -773,9 +773,9 @@ struct bNode *nodeGetActiveTexture(struct bNodeTree *ntree);
struct bNode *nodeGetActivePaintCanvas(struct bNodeTree *ntree);
/**
* @brief Does the given node supports the sub active flag.
* \brief Does the given node supports the sub active flag.
*
* @param sub_active The active flag to check. NODE_ACTIVE_TEXTURE/NODE_ACTIVE_PAINT_CANVAS
* \param sub_active: The active flag to check. #NODE_ACTIVE_TEXTURE / #NODE_ACTIVE_PAINT_CANVAS.
*/
bool nodeSupportsActiveFlag(const struct bNode *node, int sub_active);

View File

@ -272,6 +272,17 @@ void BKE_object_apply_mat4(struct Object *ob,
const float mat[4][4],
bool use_compat,
bool use_parent);
/**
* Use parent's world location and rotation as the child's origin. The parent inverse will
* become identity when the parent has no shearing. Otherwise, it is non-identity and contains the
* object's local matrix data that cannot be decomposed into location, rotation and scale.
*
* Assumes the object's world matrix has no shear.
* Assumes parent exists.
*/
void BKE_object_apply_parent_inverse(struct Object *ob);
void BKE_object_matrix_local_get(struct Object *ob, float r_mat[4][4]);
bool BKE_object_pose_context_check(const struct Object *ob);

View File

@ -49,6 +49,7 @@ struct Object;
struct PBVH;
struct Paint;
struct PaintCurve;
struct PaintModeSettings;
struct Palette;
struct PaletteColor;
struct Scene;
@ -1019,6 +1020,12 @@ enum {
SCULPT_MASK_LAYER_CALC_LOOP = (1 << 1),
};
/* paint_canvas.cc */
struct Image *BKE_paint_canvas_image_get(const struct PaintModeSettings *settings,
struct Object *ob);
int BKE_paint_canvas_uvmap_layer_index_get(const struct PaintModeSettings *settings,
struct Object *ob);
#ifdef __cplusplus
}
#endif

View File

@ -124,7 +124,7 @@ void BKE_rigidbody_validate_sim_world(struct Scene *scene,
/**
* Helper function to calculate volume of rigid-body object.
*
* TODO: allow a parameter to specify method used to calculate this?
*/
void BKE_rigidbody_calc_volume(struct Object *ob, float *r_vol);

View File

@ -121,6 +121,7 @@ set(SRC
intern/curve_eval.cc
intern/curvemapping_cache.c
intern/curve_nurbs.cc
intern/curve_poly.cc
intern/curve_to_mesh_convert.cc
intern/curveprofile.cc
intern/curves.cc
@ -135,7 +136,7 @@ set(SRC
intern/editlattice.c
intern/editmesh.c
intern/editmesh_bvh.c
intern/editmesh_cache.c
intern/editmesh_cache.cc
intern/editmesh_tangent.c
intern/effect.c
intern/fcurve.c
@ -212,12 +213,12 @@ set(SRC
intern/mesh_normals.cc
intern/mesh_remap.c
intern/mesh_remesh_voxel.cc
intern/mesh_runtime.c
intern/mesh_runtime.cc
intern/mesh_sample.cc
intern/mesh_tangent.c
intern/mesh_tessellate.c
intern/mesh_validate.cc
intern/mesh_wrapper.c
intern/mesh_wrapper.cc
intern/modifier.c
intern/movieclip.c
intern/multires.c
@ -244,6 +245,7 @@ set(SRC
intern/outliner_treehash.c
intern/packedFile.c
intern/paint.c
intern/paint_canvas.cc
intern/paint_toolslots.c
intern/particle.c
intern/particle_child.c

View File

@ -295,10 +295,12 @@ bool BKE_where_on_path(const Object *ob,
key_curve_tangent_weights(frac, w, KEY_BSPLINE);
interp_v3_v3v3v3v3(r_dir, p0->vec, p1->vec, p2->vec, p3->vec, w);
if (r_dir) {
interp_v3_v3v3v3v3(r_dir, p0->vec, p1->vec, p2->vec, p3->vec, w);
/* Make compatible with #vec_to_quat. */
negate_v3(r_dir);
/* Make compatible with #vec_to_quat. */
negate_v3(r_dir);
}
//}
const ListBase *nurbs = BKE_curve_editNurbs_get(cu);

File diff suppressed because it is too large Load Diff

View File

@ -405,8 +405,8 @@ static void splineik_evaluate_bone(
if (pchan->bone->length < FLT_EPSILON) {
/* Only move the bone position with zero length bones. */
float bone_pos[4], dir[3], rad;
BKE_where_on_path(ik_data->tar, state->curve_position, bone_pos, dir, NULL, &rad, NULL);
float bone_pos[4], rad;
BKE_where_on_path(ik_data->tar, state->curve_position, bone_pos, NULL, NULL, &rad, NULL);
apply_curve_transform(ik_data, ob, rad, bone_pos, &rad);
@ -445,13 +445,13 @@ static void splineik_evaluate_bone(
/* Step 1: determine the positions for the endpoints of the bone. */
if (point_start < 1.0f) {
float vec[4], dir[3], rad;
float vec[4], rad;
radius = 0.0f;
/* Calculate head position. */
if (point_start == 0.0f) {
/* Start of the path. We have no previous tail position to copy. */
BKE_where_on_path(ik_data->tar, point_start, vec, dir, NULL, &rad, NULL);
BKE_where_on_path(ik_data->tar, point_start, vec, NULL, NULL, &rad, NULL);
}
else {
copy_v3_v3(vec, state->prev_tail_loc);
@ -486,7 +486,7 @@ static void splineik_evaluate_bone(
}
else {
/* Scale to fit curve end position. */
if (BKE_where_on_path(ik_data->tar, point_end, vec, dir, NULL, &rad, NULL)) {
if (BKE_where_on_path(ik_data->tar, point_end, vec, NULL, NULL, &rad, NULL)) {
state->prev_tail_radius = rad;
copy_v3_v3(state->prev_tail_loc, vec);
copy_v3_v3(pose_tail, vec);

View File

@ -292,7 +292,7 @@ int BKE_id_attributes_length(const ID *id, AttributeDomainMask domain_mask, Cust
return length;
}
AttributeDomain BKE_id_attribute_domain(ID *id, const CustomDataLayer *layer)
AttributeDomain BKE_id_attribute_domain(const ID *id, const CustomDataLayer *layer)
{
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
@ -449,7 +449,7 @@ CustomDataLayer *BKE_id_attribute_from_index(ID *id,
for (int i = 0; i < customdata->totlayer; i++) {
if (!(layer_mask & CD_TYPE_AS_MASK(customdata->layers[i].type)) ||
(CD_TYPE_AS_MASK(customdata->layers[i].type) & CD_FLAG_TEMPORARY)) {
(customdata->layers[i].flag & CD_FLAG_TEMPORARY)) {
continue;
}
@ -502,7 +502,7 @@ int BKE_id_attribute_to_index(const struct ID *id,
CustomDataLayer *layer_iter = cdata->layers + j;
if (!(CD_TYPE_AS_MASK(layer_iter->type) & layer_mask) ||
(CD_TYPE_AS_MASK(layer_iter->type) & CD_FLAG_TEMPORARY)) {
(layer_iter->flag & CD_FLAG_TEMPORARY)) {
continue;
}
@ -539,8 +539,7 @@ CustomDataLayer *BKE_id_attribute_subset_active_get(const ID *id,
for (int j = 0; j < cdata->totlayer; j++) {
CustomDataLayer *layer = cdata->layers + j;
if (!(CD_TYPE_AS_MASK(layer->type) & mask) ||
(CD_TYPE_AS_MASK(layer->flag) & CD_FLAG_TEMPORARY)) {
if (!(CD_TYPE_AS_MASK(layer->type) & mask) || (layer->flag & CD_FLAG_TEMPORARY)) {
continue;
}
@ -579,8 +578,7 @@ void BKE_id_attribute_subset_active_set(ID *id,
for (int j = 0; j < cdata->totlayer; j++) {
CustomDataLayer *layer_iter = cdata->layers + j;
if (!(CD_TYPE_AS_MASK(layer_iter->type) & mask) ||
(CD_TYPE_AS_MASK(layer_iter->type) & CD_FLAG_TEMPORARY)) {
if (!(CD_TYPE_AS_MASK(layer_iter->type) & mask) || (layer_iter->flag & CD_FLAG_TEMPORARY)) {
continue;
}

View File

@ -746,15 +746,14 @@ bool CustomDataAttributes::create_by_move(const AttributeIDRef &attribute_id,
bool CustomDataAttributes::remove(const AttributeIDRef &attribute_id)
{
bool result = false;
for (const int i : IndexRange(data.totlayer)) {
const CustomDataLayer &layer = data.layers[i];
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
CustomData_free_layer(&data, layer.type, size_, i);
result = true;
return true;
}
}
return result;
return false;
}
void CustomDataAttributes::reallocate(const int size)

View File

@ -1187,6 +1187,11 @@ void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *
BLI_assert(ID_IS_LINKED(id));
BLI_assert(id->newid != NULL);
/* Do NOT delete a linked data that was already linked before this append. */
if (id->tag & LIB_TAG_PRE_EXISTING) {
continue;
}
id->tag |= LIB_TAG_DOIT;
item->new_id = id->newid;
}

View File

@ -698,12 +698,12 @@ static bool camera_frame_fit_calc_from_data(CameraParams *params,
add_v3_v3v3(plane_isect_1_other, plane_isect_1, plane_isect_1_no);
add_v3_v3v3(plane_isect_2_other, plane_isect_2, plane_isect_2_no);
if (!isect_line_line_v3(plane_isect_1,
plane_isect_1_other,
plane_isect_2,
plane_isect_2_other,
plane_isect_pt_1,
plane_isect_pt_2) != 0) {
if (isect_line_line_v3(plane_isect_1,
plane_isect_1_other,
plane_isect_2,
plane_isect_2_other,
plane_isect_pt_1,
plane_isect_pt_2) == 0) {
return false;
}

View File

@ -360,7 +360,7 @@ IDTypeInfo IDType_ID_GR = {
.name = "Collection",
.name_plural = "collections",
.translation_context = BLT_I18NCONTEXT_ID_COLLECTION,
.flags = IDTYPE_FLAGS_NO_ANIMDATA,
.flags = IDTYPE_FLAGS_NO_ANIMDATA | IDTYPE_FLAGS_APPEND_IS_REUSABLE,
.asset_type_info = NULL,
.init_data = collection_init_data,

View File

@ -888,7 +888,7 @@ static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph),
/* This following macro should be used for all standard single-target *_get_tars functions
* to save typing and reduce maintenance woes. It does not do the subtarget related operations
* (Hopefully all compilers will be happy with the lines with just a space on them. Those are
* really just to help this code easier to read)
* really just to help this code easier to read)
*/
/* TODO: cope with getting rotation order... */
#define SINGLETARGETNS_GET_TARS(con, datatar, ct, list) \
@ -932,7 +932,7 @@ static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph),
* to save typing and reduce maintenance woes. It does not do the subtarget related operations.
* NOTE: the pointer to ct will be changed to point to the next in the list (as it gets removed)
* (Hopefully all compilers will be happy with the lines with just a space on them. Those are
* really just to help this code easier to read)
* really just to help this code easier to read)
*/
#define SINGLETARGETNS_FLUSH_TARS(con, datatar, ct, list, no_copy) \
{ \
@ -1495,7 +1495,7 @@ static void followpath_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_CURVES_LEGACY)) {
Curve *cu = ct->tar->data;
float vec[4], dir[3], radius;
float vec[4], radius;
float curvetime;
unit_m4(ct->matrix);
@ -1532,7 +1532,7 @@ static void followpath_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
if (BKE_where_on_path(ct->tar,
curvetime,
vec,
dir,
NULL,
(data->followflag & FOLLOWPATH_FOLLOW) ? quat : NULL,
&radius,
NULL)) { /* quat_pt is quat or NULL. */
@ -3886,7 +3886,7 @@ static void clampto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
/* get targetmatrix */
if (data->tar->runtime.curve_cache && data->tar->runtime.curve_cache->anim_path_accum_length) {
float vec[4], dir[3], totmat[4][4];
float vec[4], totmat[4][4];
float curvetime;
short clamp_axis;
@ -3969,7 +3969,7 @@ static void clampto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
}
/* 3. position on curve */
if (BKE_where_on_path(ct->tar, curvetime, vec, dir, NULL, NULL, NULL)) {
if (BKE_where_on_path(ct->tar, curvetime, vec, NULL, NULL, NULL, NULL)) {
unit_m4(totmat);
copy_v3_v3(totmat[3], vec);

View File

@ -665,7 +665,7 @@ Nurb *BKE_nurb_duplicate(const Nurb *nu)
if (newnu == nullptr) {
return nullptr;
}
memcpy(newnu, nu, sizeof(Nurb));
*newnu = blender::dna::shallow_copy(*nu);
if (nu->bezt) {
newnu->bezt = (BezTriple *)MEM_malloc_arrayN(nu->pntsu, sizeof(BezTriple), "duplicateNurb2");
@ -699,7 +699,7 @@ Nurb *BKE_nurb_duplicate(const Nurb *nu)
Nurb *BKE_nurb_copy(Nurb *src, int pntsu, int pntsv)
{
Nurb *newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "copyNurb");
memcpy(newnu, src, sizeof(Nurb));
*newnu = blender::dna::shallow_copy(*src);
if (pntsu == 1) {
SWAP(int, pntsu, pntsv);

View File

@ -281,6 +281,11 @@ static void interpolate_to_evaluated(const Span<T> src,
BLI_assert(!src.is_empty());
BLI_assert(evaluated_offsets.size() == src.size());
BLI_assert(evaluated_offsets.last() == dst.size());
if (src.size() == 1) {
BLI_assert(dst.size() == 1);
dst.first() = src.first();
return;
}
linear_interpolation(src.first(), src[1], dst.take_front(evaluated_offsets.first()));

View File

@ -381,11 +381,12 @@ std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves)
curves.geometry);
VArray<int> resolution = geometry.resolution();
VArray<int8_t> normal_mode = geometry.normal_mode();
VArray_Span<float> nurbs_weights{
src_component.attribute_get_for_read<float>("nurbs_weight", ATTR_DOMAIN_POINT, 0.0f)};
VArray_Span<int> nurbs_orders{
src_component.attribute_get_for_read<int>("nurbs_order", ATTR_DOMAIN_CURVE, 4)};
VArray_Span<int8_t> nurbs_orders{
src_component.attribute_get_for_read<int8_t>("nurbs_order", ATTR_DOMAIN_CURVE, 4)};
VArray_Span<int8_t> nurbs_knots_modes{
src_component.attribute_get_for_read<int8_t>("knots_mode", ATTR_DOMAIN_CURVE, 0)};
@ -436,6 +437,7 @@ std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves)
spline->positions().fill(float3(0));
spline->tilts().fill(0.0f);
spline->radii().fill(1.0f);
spline->normal_mode = static_cast<NormalMode>(normal_mode[curve_index]);
curve_eval->add_spline(std::move(spline));
}
@ -448,6 +450,7 @@ std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves)
dst_component,
{"curve_type",
"resolution",
"normal_mode",
"nurbs_weight",
"nurbs_order",
"knots_mode",
@ -468,6 +471,8 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval)
geometry.offsets_for_write().copy_from(curve_eval.control_point_offsets());
MutableSpan<int8_t> curve_types = geometry.curve_types_for_write();
OutputAttribute_Typed<int8_t> normal_mode =
dst_component.attribute_try_get_for_output_only<int8_t>("normal_mode", ATTR_DOMAIN_CURVE);
OutputAttribute_Typed<float> nurbs_weight;
OutputAttribute_Typed<int> nurbs_order;
OutputAttribute_Typed<int8_t> nurbs_knots_mode;
@ -491,7 +496,7 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval)
for (const int curve_index : curve_eval.splines().index_range()) {
const Spline &spline = *curve_eval.splines()[curve_index];
curve_types[curve_index] = curve_eval.splines()[curve_index]->type();
normal_mode.as_span()[curve_index] = curve_eval.splines()[curve_index]->normal_mode;
const IndexRange point_range = geometry.points_for_curve(curve_index);
switch (spline.type()) {
@ -517,6 +522,7 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval)
}
}
normal_mode.save();
nurbs_weight.save();
nurbs_order.save();
nurbs_knots_mode.save();

View File

@ -0,0 +1,154 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup bke
*/
#include <algorithm>
#include "BLI_math_vector.h"
#include "BLI_math_vector.hh"
#include "BKE_curves.hh"
namespace blender::bke::curves::poly {
static float3 direction_bisect(const float3 &prev, const float3 &middle, const float3 &next)
{
const float3 dir_prev = math::normalize(middle - prev);
const float3 dir_next = math::normalize(next - middle);
const float3 result = math::normalize(dir_prev + dir_next);
if (UNLIKELY(math::is_zero(result))) {
return float3(0.0f, 0.0f, 1.0f);
}
return result;
}
void calculate_tangents(const Span<float3> positions,
const bool is_cyclic,
MutableSpan<float3> tangents)
{
BLI_assert(positions.size() == tangents.size());
if (positions.size() == 1) {
tangents.first() = float3(0.0f, 0.0f, 1.0f);
return;
}
for (const int i : IndexRange(1, positions.size() - 2)) {
tangents[i] = direction_bisect(positions[i - 1], positions[i], positions[i + 1]);
}
if (is_cyclic) {
const float3 &second_to_last = positions[positions.size() - 2];
const float3 &last = positions.last();
const float3 &first = positions.first();
const float3 &second = positions[1];
tangents.first() = direction_bisect(last, first, second);
tangents.last() = direction_bisect(second_to_last, last, first);
}
else {
tangents.first() = math::normalize(positions[1] - positions.first());
tangents.last() = math::normalize(positions.last() - positions[positions.size() - 2]);
}
}
static float3 rotate_direction_around_axis(const float3 &direction,
const float3 &axis,
const float angle)
{
BLI_ASSERT_UNIT_V3(direction);
BLI_ASSERT_UNIT_V3(axis);
const float3 axis_scaled = axis * math::dot(direction, axis);
const float3 diff = direction - axis_scaled;
const float3 cross = math::cross(axis, diff);
return axis_scaled + diff * std::cos(angle) + cross * std::sin(angle);
}
void calculate_normals_z_up(const Span<float3> tangents, MutableSpan<float3> normals)
{
BLI_assert(normals.size() == tangents.size());
/* Same as in `vec_to_quat`. */
const float epsilon = 1e-4f;
for (const int i : normals.index_range()) {
const float3 &tangent = tangents[i];
if (std::abs(tangent.x) + std::abs(tangent.y) < epsilon) {
normals[i] = {1.0f, 0.0f, 0.0f};
}
else {
normals[i] = math::normalize(float3(tangent.y, -tangent.x, 0.0f));
}
}
}
/**
* Rotate the last normal in the same way the tangent has been rotated.
*/
static float3 calculate_next_normal(const float3 &last_normal,
const float3 &last_tangent,
const float3 &current_tangent)
{
if (math::is_zero(last_tangent) || math::is_zero(current_tangent)) {
return last_normal;
}
const float angle = angle_normalized_v3v3(last_tangent, current_tangent);
if (angle != 0.0) {
const float3 axis = math::normalize(math::cross(last_tangent, current_tangent));
return rotate_direction_around_axis(last_normal, axis, angle);
}
return last_normal;
}
void calculate_normals_minimum(const Span<float3> tangents,
const bool cyclic,
MutableSpan<float3> normals)
{
BLI_assert(normals.size() == tangents.size());
if (normals.is_empty()) {
return;
}
const float epsilon = 1e-4f;
/* Set initial normal. */
const float3 &first_tangent = tangents.first();
if (fabs(first_tangent.x) + fabs(first_tangent.y) < epsilon) {
normals.first() = {1.0f, 0.0f, 0.0f};
}
else {
normals.first() = math::normalize(float3(first_tangent.y, -first_tangent.x, 0.0f));
}
/* Forward normal with minimum twist along the entire spline. */
for (const int i : IndexRange(1, normals.size() - 1)) {
normals[i] = calculate_next_normal(normals[i - 1], tangents[i - 1], tangents[i]);
}
if (!cyclic) {
return;
}
/* Compute how much the first normal deviates from the normal that has been forwarded along the
* entire cyclic spline. */
const float3 uncorrected_last_normal = calculate_next_normal(
normals.last(), tangents.last(), tangents.first());
float correction_angle = angle_signed_on_axis_v3v3_v3(
normals.first(), uncorrected_last_normal, tangents.first());
if (correction_angle > M_PI) {
correction_angle = correction_angle - 2 * M_PI;
}
/* Gradually apply correction by rotating all normals slightly. */
const float angle_step = correction_angle / normals.size();
for (const int i : normals.index_range()) {
const float angle = angle_step * i;
normals[i] = rotate_direction_around_axis(normals[i], tangents[i], angle);
}
}
} // namespace blender::bke::curves::poly

View File

@ -25,6 +25,7 @@ static const std::string ATTR_RADIUS = "radius";
static const std::string ATTR_CURVE_TYPE = "curve_type";
static const std::string ATTR_CYCLIC = "cyclic";
static const std::string ATTR_RESOLUTION = "resolution";
static const std::string ATTR_NORMAL_MODE = "normal_mode";
static const std::string ATTR_HANDLE_TYPE_LEFT = "handle_type_left";
static const std::string ATTR_HANDLE_TYPE_RIGHT = "handle_type_right";
static const std::string ATTR_HANDLE_POSITION_LEFT = "handle_left";
@ -202,7 +203,8 @@ static Span<T> get_span_attribute(const CurvesGeometry &curves,
template<typename T>
static MutableSpan<T> get_mutable_attribute(CurvesGeometry &curves,
const AttributeDomain domain,
const StringRefNull name)
const StringRefNull name,
const T default_value = T())
{
const int size = domain_size(curves, domain);
const CustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>());
@ -215,7 +217,11 @@ static MutableSpan<T> get_mutable_attribute(CurvesGeometry &curves,
}
data = (T *)CustomData_add_layer_named(
&custom_data, type, CD_CALLOC, nullptr, size, name.c_str());
return {data, size};
MutableSpan<T> span = {data, size};
if (size > 0 && span.first() != default_value) {
span.fill(default_value);
}
return span;
}
VArray<int8_t> CurvesGeometry::curve_types() const
@ -303,7 +309,7 @@ VArray<bool> CurvesGeometry::cyclic() const
}
MutableSpan<bool> CurvesGeometry::cyclic_for_write()
{
return get_mutable_attribute<bool>(*this, ATTR_DOMAIN_CURVE, ATTR_CYCLIC);
return get_mutable_attribute<bool>(*this, ATTR_DOMAIN_CURVE, ATTR_CYCLIC, false);
}
VArray<int> CurvesGeometry::resolution() const
@ -312,7 +318,16 @@ VArray<int> CurvesGeometry::resolution() const
}
MutableSpan<int> CurvesGeometry::resolution_for_write()
{
return get_mutable_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_RESOLUTION);
return get_mutable_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_RESOLUTION, 12);
}
VArray<int8_t> CurvesGeometry::normal_mode() const
{
return get_varray_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NORMAL_MODE, 0);
}
MutableSpan<int8_t> CurvesGeometry::normal_mode_for_write()
{
return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NORMAL_MODE);
}
VArray<int8_t> CurvesGeometry::handle_types_left() const
@ -321,7 +336,7 @@ VArray<int8_t> CurvesGeometry::handle_types_left() const
}
MutableSpan<int8_t> CurvesGeometry::handle_types_left_for_write()
{
return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_POINT, ATTR_HANDLE_TYPE_LEFT);
return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_POINT, ATTR_HANDLE_TYPE_LEFT, 0);
}
VArray<int8_t> CurvesGeometry::handle_types_right() const
@ -330,7 +345,7 @@ VArray<int8_t> CurvesGeometry::handle_types_right() const
}
MutableSpan<int8_t> CurvesGeometry::handle_types_right_for_write()
{
return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_POINT, ATTR_HANDLE_TYPE_RIGHT);
return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_POINT, ATTR_HANDLE_TYPE_RIGHT, 0);
}
Span<float3> CurvesGeometry::handle_positions_left() const
@ -357,7 +372,7 @@ VArray<int8_t> CurvesGeometry::nurbs_orders() const
}
MutableSpan<int8_t> CurvesGeometry::nurbs_orders_for_write()
{
return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NURBS_ORDER);
return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NURBS_ORDER, 4);
}
Span<float> CurvesGeometry::nurbs_weights() const
@ -375,7 +390,7 @@ VArray<int8_t> CurvesGeometry::nurbs_knots_modes() const
}
MutableSpan<int8_t> CurvesGeometry::nurbs_knots_modes_for_write()
{
return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NURBS_KNOTS_MODE);
return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NURBS_KNOTS_MODE, 0);
}
VArray<int> CurvesGeometry::surface_triangle_indices() const
@ -385,7 +400,7 @@ VArray<int> CurvesGeometry::surface_triangle_indices() const
MutableSpan<int> CurvesGeometry::surface_triangle_indices_for_write()
{
return get_mutable_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_INDEX);
return get_mutable_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_INDEX, -1);
}
Span<float2> CurvesGeometry::surface_triangle_coords() const
@ -562,18 +577,25 @@ void CurvesGeometry::ensure_nurbs_basis_cache() const
Span<float3> CurvesGeometry::evaluated_positions() const
{
if (!this->runtime->position_cache_dirty) {
return this->runtime->evaluated_position_cache;
return this->runtime->evaluated_positions_span;
}
/* A double checked lock. */
std::scoped_lock lock{this->runtime->position_cache_mutex};
if (!this->runtime->position_cache_dirty) {
return this->runtime->evaluated_position_cache;
return this->runtime->evaluated_positions_span;
}
threading::isolate_task([&]() {
if (this->is_single_type(CURVE_TYPE_POLY)) {
this->runtime->evaluated_positions_span = this->positions();
this->runtime->evaluated_position_cache.clear_and_make_inline();
return;
}
this->runtime->evaluated_position_cache.resize(this->evaluated_points_num());
MutableSpan<float3> evaluated_positions = this->runtime->evaluated_position_cache;
this->runtime->evaluated_positions_span = evaluated_positions;
VArray<int8_t> types = this->curve_types();
VArray<bool> cyclic = this->cyclic();
@ -630,7 +652,114 @@ Span<float3> CurvesGeometry::evaluated_positions() const
});
this->runtime->position_cache_dirty = false;
return this->runtime->evaluated_position_cache;
return this->runtime->evaluated_positions_span;
}
Span<float3> CurvesGeometry::evaluated_tangents() const
{
if (!this->runtime->tangent_cache_dirty) {
return this->runtime->evaluated_tangent_cache;
}
/* A double checked lock. */
std::scoped_lock lock{this->runtime->tangent_cache_mutex};
if (!this->runtime->tangent_cache_dirty) {
return this->runtime->evaluated_tangent_cache;
}
threading::isolate_task([&]() {
const Span<float3> evaluated_positions = this->evaluated_positions();
const VArray<bool> cyclic = this->cyclic();
this->runtime->evaluated_tangent_cache.resize(this->evaluated_points_num());
MutableSpan<float3> tangents = this->runtime->evaluated_tangent_cache;
threading::parallel_for(this->curves_range(), 128, [&](IndexRange curves_range) {
for (const int curve_index : curves_range) {
const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index);
if (UNLIKELY(evaluated_points.is_empty())) {
continue;
}
curves::poly::calculate_tangents(evaluated_positions.slice(evaluated_points),
cyclic[curve_index],
tangents.slice(evaluated_points));
}
});
/* Correct the first and last tangents of Bezier curves so that they align with the inner
* handles. This is a separate loop to avoid the cost when Bezier type curves are not used. */
Vector<int64_t> bezier_indices;
const IndexMask bezier_mask = this->indices_for_curve_type(CURVE_TYPE_BEZIER, bezier_indices);
if (!bezier_mask.is_empty()) {
const Span<float3> positions = this->positions();
const Span<float3> handles_left = this->handle_positions_left();
const Span<float3> handles_right = this->handle_positions_right();
threading::parallel_for(bezier_mask.index_range(), 1024, [&](IndexRange range) {
for (const int curve_index : bezier_mask.slice(range)) {
const IndexRange points = this->points_for_curve(curve_index);
const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index);
if (handles_right[points.first()] != positions[points.first()]) {
tangents[evaluated_points.first()] = math::normalize(handles_right[points.first()] -
positions[points.first()]);
}
if (handles_left[points.last()] != positions[points.last()]) {
tangents[evaluated_points.last()] = math::normalize(positions[points.last()] -
handles_left[points.last()]);
}
}
});
}
});
this->runtime->tangent_cache_dirty = false;
return this->runtime->evaluated_tangent_cache;
}
Span<float3> CurvesGeometry::evaluated_normals() const
{
if (!this->runtime->normal_cache_dirty) {
return this->runtime->evaluated_normal_cache;
}
/* A double checked lock. */
std::scoped_lock lock{this->runtime->normal_cache_mutex};
if (!this->runtime->normal_cache_dirty) {
return this->runtime->evaluated_normal_cache;
}
threading::isolate_task([&]() {
const Span<float3> evaluated_tangents = this->evaluated_tangents();
const VArray<bool> cyclic = this->cyclic();
const VArray<int8_t> normal_mode = this->normal_mode();
this->runtime->evaluated_normal_cache.resize(this->evaluated_points_num());
MutableSpan<float3> evaluated_normals = this->runtime->evaluated_normal_cache;
threading::parallel_for(this->curves_range(), 128, [&](IndexRange curves_range) {
for (const int curve_index : curves_range) {
const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index);
if (UNLIKELY(evaluated_points.is_empty())) {
continue;
}
switch (normal_mode[curve_index]) {
case NORMAL_MODE_Z_UP:
curves::poly::calculate_normals_z_up(evaluated_tangents.slice(evaluated_points),
evaluated_normals.slice(evaluated_points));
break;
case NORMAL_MODE_MINIMUM_TWIST:
curves::poly::calculate_normals_minimum(evaluated_tangents.slice(evaluated_points),
cyclic[curve_index],
evaluated_normals.slice(evaluated_points));
break;
}
}
});
});
this->runtime->normal_cache_dirty = false;
return this->runtime->evaluated_normal_cache;
}
void CurvesGeometry::interpolate_to_evaluated(const int curve_index,

View File

@ -214,18 +214,14 @@ float (*BKE_editmesh_vert_coords_alloc(struct Depsgraph *depsgraph,
Object *ob,
int *r_vert_len))[3]
{
Mesh *cage;
BLI_bitmap *visit_bitmap;
Mesh *cage = editbmesh_get_eval_cage(depsgraph, scene, ob, em, &CD_MASK_BAREMESH);
float(*cos_cage)[3] = MEM_callocN(sizeof(*cos_cage) * em->bm->totvert, "bmbvh cos_cage");
/* When initializing cage verts, we only want the first cage coordinate for each vertex,
* so that e.g. mirror or array use original vertex coordinates and not mirrored or duplicate. */
BLI_bitmap *visit_bitmap = BLI_BITMAP_NEW(em->bm->totvert, __func__);
struct CageUserData data;
float(*cos_cage)[3];
cage = editbmesh_get_eval_cage(depsgraph, scene, ob, em, &CD_MASK_BAREMESH);
cos_cage = MEM_callocN(sizeof(*cos_cage) * em->bm->totvert, "bmbvh cos_cage");
/* when initializing cage verts, we only want the first cage coordinate for each vertex,
* so that e.g. mirror or array use original vertex coordinates and not mirrored or duplicate */
visit_bitmap = BLI_BITMAP_NEW(em->bm->totvert, __func__);
data.totvert = em->bm->totvert;
data.cos_cage = cos_cage;
data.visit_bitmap = visit_bitmap;

View File

@ -8,7 +8,9 @@
#include "MEM_guardedalloc.h"
#include "BLI_bounds.hh"
#include "BLI_math_vector.h"
#include "BLI_span.hh"
#include "DNA_mesh_types.h"
@ -21,23 +23,21 @@
void BKE_editmesh_cache_ensure_poly_normals(BMEditMesh *em, EditMeshData *emd)
{
if (!(emd->vertexCos && (emd->polyNos == NULL))) {
if (!(emd->vertexCos && (emd->polyNos == nullptr))) {
return;
}
BMesh *bm = em->bm;
const float(*vertexCos)[3];
float(*polyNos)[3];
BMFace *efa;
BMIter fiter;
int i;
BM_mesh_elem_index_ensure(bm, BM_VERT);
polyNos = MEM_mallocN(sizeof(*polyNos) * bm->totface, __func__);
float(*polyNos)[3] = static_cast<float(*)[3]>(
MEM_mallocN(sizeof(*polyNos) * bm->totface, __func__));
vertexCos = emd->vertexCos;
const float(*vertexCos)[3] = emd->vertexCos;
BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
BM_elem_index_set(efa, i); /* set_inline */
@ -50,7 +50,7 @@ void BKE_editmesh_cache_ensure_poly_normals(BMEditMesh *em, EditMeshData *emd)
void BKE_editmesh_cache_ensure_vert_normals(BMEditMesh *em, EditMeshData *emd)
{
if (!(emd->vertexCos && (emd->vertexNos == NULL))) {
if (!(emd->vertexCos && (emd->vertexNos == nullptr))) {
return;
}
@ -58,14 +58,14 @@ void BKE_editmesh_cache_ensure_vert_normals(BMEditMesh *em, EditMeshData *emd)
const float(*vertexCos)[3], (*polyNos)[3];
float(*vertexNos)[3];
/* calculate vertex normals from poly normals */
/* Calculate vertex normals from poly normals. */
BKE_editmesh_cache_ensure_poly_normals(em, emd);
BM_mesh_elem_index_ensure(bm, BM_FACE);
polyNos = emd->polyNos;
vertexCos = emd->vertexCos;
vertexNos = MEM_callocN(sizeof(*vertexNos) * bm->totvert, __func__);
vertexNos = static_cast<float(*)[3]>(MEM_callocN(sizeof(*vertexNos) * bm->totvert, __func__));
BM_verts_calc_normal_vcos(bm, polyNos, vertexCos, vertexNos);
@ -74,17 +74,17 @@ void BKE_editmesh_cache_ensure_vert_normals(BMEditMesh *em, EditMeshData *emd)
void BKE_editmesh_cache_ensure_poly_centers(BMEditMesh *em, EditMeshData *emd)
{
if (emd->polyCos != NULL) {
if (emd->polyCos != nullptr) {
return;
}
BMesh *bm = em->bm;
float(*polyCos)[3];
BMFace *efa;
BMIter fiter;
int i;
polyCos = MEM_mallocN(sizeof(*polyCos) * bm->totface, __func__);
float(*polyCos)[3] = static_cast<float(*)[3]>(
MEM_mallocN(sizeof(*polyCos) * bm->totface, __func__));
if (emd->vertexCos) {
const float(*vertexCos)[3];
@ -116,18 +116,20 @@ bool BKE_editmesh_cache_calc_minmax(struct BMEditMesh *em,
float min[3],
float max[3])
{
using namespace blender;
BMesh *bm = em->bm;
BMVert *eve;
BMIter iter;
int i;
if (bm->totvert) {
if (emd->vertexCos) {
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
minmax_v3v3_v3(min, max, emd->vertexCos[i]);
}
Span<float3> vert_coords(reinterpret_cast<const float3 *>(emd->vertexCos), bm->totvert);
std::optional<bounds::MinMaxResult<float3>> bounds = bounds::min_max(vert_coords);
BLI_assert(bounds.has_value());
copy_v3_v3(min, math::min(bounds->min, float3(min)));
copy_v3_v3(max, math::max(bounds->max, float3(max)));
}
else {
BMVert *eve;
BMIter iter;
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
minmax_v3v3_v3(min, max, eve->co);
}

View File

@ -141,81 +141,97 @@ const Curve *CurveComponent::get_curve_for_render() const
namespace blender::bke {
static void calculate_bezier_normals(const BezierSpline &spline, MutableSpan<float3> normals)
static Array<float3> curve_normal_point_domain(const bke::CurvesGeometry &curves)
{
Span<int> offsets = spline.control_point_offsets();
Span<float3> evaluated_normals = spline.evaluated_normals();
for (const int i : IndexRange(spline.size())) {
normals[i] = evaluated_normals[offsets[i]];
}
}
const VArray<int8_t> types = curves.curve_types();
const VArray<int> resolutions = curves.resolution();
const VArray<bool> curves_cyclic = curves.cyclic();
static void calculate_poly_normals(const PolySpline &spline, MutableSpan<float3> normals)
{
normals.copy_from(spline.evaluated_normals());
}
const Span<float3> positions = curves.positions();
const VArray<int8_t> normal_modes = curves.normal_mode();
/**
* Because NURBS control points are not necessarily on the path, the normal at the control points
* is not well defined, so create a temporary poly spline to find the normals. This requires extra
* copying currently, but may be more efficient in the future if attributes have some form of CoW.
*/
static void calculate_nurbs_normals(const NURBSpline &spline, MutableSpan<float3> normals)
{
PolySpline poly_spline;
poly_spline.resize(spline.size());
poly_spline.positions().copy_from(spline.positions());
poly_spline.tilts().copy_from(spline.tilts());
normals.copy_from(poly_spline.evaluated_normals());
}
const Span<float3> evaluated_normals = curves.evaluated_normals();
static Array<float3> curve_normal_point_domain(const CurveEval &curve)
{
Span<SplinePtr> splines = curve.splines();
Array<int> offsets = curve.control_point_offsets();
const int total_size = offsets.last();
Array<float3> normals(total_size);
Array<float3> results(curves.points_num());
threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
const Spline &spline = *splines[i];
MutableSpan spline_normals{normals.as_mutable_span().slice(offsets[i], spline.size())};
switch (splines[i]->type()) {
case CURVE_TYPE_BEZIER:
calculate_bezier_normals(static_cast<const BezierSpline &>(spline), spline_normals);
threading::parallel_for(curves.curves_range(), 128, [&](IndexRange range) {
Vector<float3> nurbs_tangents;
for (const int i_curve : range) {
const IndexRange points = curves.points_for_curve(i_curve);
const IndexRange evaluated_points = curves.evaluated_points_for_curve(i_curve);
MutableSpan<float3> curve_normals = results.as_mutable_span().slice(points);
switch (types[i_curve]) {
case CURVE_TYPE_CATMULL_ROM: {
const Span<float3> normals = evaluated_normals.slice(evaluated_points);
const int resolution = resolutions[i_curve];
for (const int i : IndexRange(points.size())) {
curve_normals[i] = normals[resolution * i];
}
break;
}
case CURVE_TYPE_POLY:
calculate_poly_normals(static_cast<const PolySpline &>(spline), spline_normals);
curve_normals.copy_from(evaluated_normals.slice(evaluated_points));
break;
case CURVE_TYPE_NURBS:
calculate_nurbs_normals(static_cast<const NURBSpline &>(spline), spline_normals);
case CURVE_TYPE_BEZIER: {
const Span<float3> normals = evaluated_normals.slice(evaluated_points);
curve_normals.first() = normals.first();
const Span<int> offsets = curves.bezier_evaluated_offsets_for_curve(i_curve);
for (const int i : IndexRange(points.size()).drop_front(1)) {
curve_normals[i] = normals[offsets[i - 1]];
}
break;
case CURVE_TYPE_CATMULL_ROM:
BLI_assert_unreachable();
}
case CURVE_TYPE_NURBS: {
/* For NURBS curves there is no obvious correspondence between specific evaluated points
* and control points, so normals are determined by treating them as poly curves. */
nurbs_tangents.clear();
nurbs_tangents.resize(points.size());
const bool cyclic = curves_cyclic[i_curve];
const Span<float3> curve_positions = positions.slice(points);
bke::curves::poly::calculate_tangents(curve_positions, cyclic, nurbs_tangents);
switch (NormalMode(normal_modes[i_curve])) {
case NORMAL_MODE_Z_UP:
bke::curves::poly::calculate_normals_z_up(nurbs_tangents, curve_normals);
break;
case NORMAL_MODE_MINIMUM_TWIST:
bke::curves::poly::calculate_normals_minimum(nurbs_tangents, cyclic, curve_normals);
break;
}
break;
}
}
}
});
return normals;
return results;
}
VArray<float3> curve_normals_varray(const CurveComponent &component, const AttributeDomain domain)
{
if (component.is_empty()) {
return nullptr;
if (!component.has_curves()) {
return {};
}
const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_read());
const Curves &curves_id = *component.get_for_read();
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
const VArray<int8_t> types = curves.curve_types();
if (curves.is_single_type(CURVE_TYPE_POLY)) {
return component.attribute_try_adapt_domain<float3>(
VArray<float3>::ForSpan(curves.evaluated_normals()), ATTR_DOMAIN_POINT, domain);
}
Array<float3> normals = curve_normal_point_domain(curves);
if (domain == ATTR_DOMAIN_POINT) {
Array<float3> normals = curve_normal_point_domain(*curve);
return VArray<float3>::ForContainer(std::move(normals));
}
if (domain == ATTR_DOMAIN_CURVE) {
Array<float3> point_normals = curve_normal_point_domain(*curve);
VArray<float3> varray = VArray<float3>::ForContainer(std::move(point_normals));
return component.attribute_try_adapt_domain<float3>(
std::move(varray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
VArray<float3>::ForContainer(std::move(normals)), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
}
return nullptr;
@ -446,16 +462,28 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
static BuiltinCustomDataLayerProvider nurbs_order("nurbs_order",
ATTR_DOMAIN_CURVE,
CD_PROP_INT32,
CD_PROP_INT32,
CD_PROP_INT8,
CD_PROP_INT8,
BuiltinAttributeProvider::Creatable,
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::Deletable,
curve_access,
make_array_read_attribute<int>,
make_array_write_attribute<int>,
make_array_read_attribute<int8_t>,
make_array_write_attribute<int8_t>,
tag_component_topology_changed);
static BuiltinCustomDataLayerProvider normal_mode("normal_mode",
ATTR_DOMAIN_CURVE,
CD_PROP_INT8,
CD_PROP_INT8,
BuiltinAttributeProvider::Creatable,
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::Deletable,
curve_access,
make_array_read_attribute<int8_t>,
make_array_write_attribute<int8_t>,
tag_component_normals_changed);
static BuiltinCustomDataLayerProvider nurbs_knots_mode("knots_mode",
ATTR_DOMAIN_CURVE,
CD_PROP_INT8,
@ -515,7 +543,9 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
&handle_left,
&handle_type_right,
&handle_type_left,
&normal_mode,
&nurbs_order,
&nurbs_knots_mode,
&nurbs_weight,
&curve_type,
&resolution,

View File

@ -50,7 +50,12 @@ GeometrySet object_get_evaluated_geometry_set(const Object &object)
return geometry_set;
}
if (object.runtime.geometry_set_eval != nullptr) {
return *object.runtime.geometry_set_eval;
GeometrySet geometry_set = *object.runtime.geometry_set_eval;
/* Ensure that subdivision is performed on the CPU. */
if (geometry_set.has_mesh()) {
add_final_mesh_as_geometry_component(object, geometry_set);
}
return geometry_set;
}
/* Otherwise, construct a new geometry set with the component based on the object type. */

View File

@ -1806,9 +1806,9 @@ void BKE_image_stamp_buf(Scene *scene,
int channels)
{
struct StampData stamp_data;
float w, h, pad;
int w, h, pad;
int x, y, y_ofs;
float h_fixed;
int h_fixed;
const int mono = blf_mono_font_render; /* XXX */
struct ColorManagedDisplay *display;
const char *display_device;
@ -1816,20 +1816,20 @@ void BKE_image_stamp_buf(Scene *scene,
/* vars for calculating wordwrap */
struct {
struct ResultBLF info;
rctf rect;
rcti rect;
} wrap;
/* this could be an argument if we want to operate on non linear float imbuf's
* for now though this is only used for renders which use scene settings */
#define TEXT_SIZE_CHECK(str, w, h) \
((str[0]) && ((void)(h = h_fixed), (w = BLF_width(mono, str, sizeof(str)))))
((str[0]) && ((void)(h = h_fixed), (w = (int)BLF_width(mono, str, sizeof(str)))))
/* must enable BLF_WORD_WRAP before using */
#define TEXT_SIZE_CHECK_WORD_WRAP(str, w, h) \
((str[0]) && (BLF_boundbox_ex(mono, str, sizeof(str), &wrap.rect, &wrap.info), \
(void)(h = h_fixed * wrap.info.lines), \
(w = BLI_rctf_size_x(&wrap.rect))))
(w = BLI_rcti_size_x(&wrap.rect))))
#define BUFF_MARGIN_X 2
#define BUFF_MARGIN_Y 1
@ -3096,7 +3096,7 @@ void BKE_image_get_tile_label(Image *ima, ImageTile *tile, char *label, int len_
}
}
bool BKE_image_get_tile_info(char *filepath, ListBase *tiles, int *tile_start, int *tile_range)
bool BKE_image_get_tile_info(char *filepath, ListBase *tiles, int *r_tile_start, int *r_tile_range)
{
char filename[FILE_MAXFILE], dirname[FILE_MAXDIR];
BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename));
@ -3138,8 +3138,8 @@ bool BKE_image_get_tile_info(char *filepath, ListBase *tiles, int *tile_start, i
if (is_udim && min_udim <= IMA_UDIM_MAX) {
BLI_join_dirfile(filepath, FILE_MAX, dirname, filename);
*tile_start = min_udim;
*tile_range = max_udim - min_udim + 1;
*r_tile_start = min_udim;
*r_tile_range = max_udim - min_udim + 1;
return true;
}
return false;

View File

@ -69,7 +69,7 @@ static void test_lattice_deform_free(LatticeDeformTestContext *ctx)
TEST(lattice_deform_performance, performance_no_dvert_1)
{
const int32_t num_items = 1;
LatticeDeformTestContext ctx = {{{nullptr}}};
LatticeDeformTestContext ctx = {dna::shallow_zero_initialize()};
RandomNumberGenerator rng;
test_lattice_deform_init(&ctx, &rng, num_items);
test_lattice_deform(&ctx, num_items);
@ -78,7 +78,7 @@ TEST(lattice_deform_performance, performance_no_dvert_1)
TEST(lattice_deform_performance, performance_no_dvert_1000)
{
const int32_t num_items = 1000;
LatticeDeformTestContext ctx = {{{nullptr}}};
LatticeDeformTestContext ctx = {dna::shallow_zero_initialize()};
RandomNumberGenerator rng;
test_lattice_deform_init(&ctx, &rng, num_items);
test_lattice_deform(&ctx, num_items);
@ -87,7 +87,7 @@ TEST(lattice_deform_performance, performance_no_dvert_1000)
TEST(lattice_deform_performance, performance_no_dvert_10000)
{
const int32_t num_items = 10000;
LatticeDeformTestContext ctx = {{{nullptr}}};
LatticeDeformTestContext ctx = {dna::shallow_zero_initialize()};
RandomNumberGenerator rng;
test_lattice_deform_init(&ctx, &rng, num_items);
test_lattice_deform(&ctx, num_items);
@ -96,7 +96,7 @@ TEST(lattice_deform_performance, performance_no_dvert_10000)
TEST(lattice_deform_performance, performance_no_dvert_100000)
{
const int32_t num_items = 100000;
LatticeDeformTestContext ctx = {{{nullptr}}};
LatticeDeformTestContext ctx = {dna::shallow_zero_initialize()};
RandomNumberGenerator rng;
test_lattice_deform_init(&ctx, &rng, num_items);
test_lattice_deform(&ctx, num_items);
@ -105,7 +105,7 @@ TEST(lattice_deform_performance, performance_no_dvert_100000)
TEST(lattice_deform_performance, performance_no_dvert_1000000)
{
const int32_t num_items = 1000000;
LatticeDeformTestContext ctx = {{{nullptr}}};
LatticeDeformTestContext ctx = {dna::shallow_zero_initialize()};
RandomNumberGenerator rng;
test_lattice_deform_init(&ctx, &rng, num_items);
test_lattice_deform(&ctx, num_items);
@ -114,7 +114,7 @@ TEST(lattice_deform_performance, performance_no_dvert_1000000)
TEST(lattice_deform_performance, performance_no_dvert_10000000)
{
const int32_t num_items = 10000000;
LatticeDeformTestContext ctx = {{{nullptr}}};
LatticeDeformTestContext ctx = {dna::shallow_zero_initialize()};
RandomNumberGenerator rng;
test_lattice_deform_init(&ctx, &rng, num_items);
test_lattice_deform(&ctx, num_items);

View File

@ -1658,7 +1658,10 @@ static void layer_collection_local_sync(ViewLayer *view_layer,
if (visible) {
LISTBASE_FOREACH (CollectionObject *, cob, &layer_collection->collection->gobject) {
BLI_assert(cob->ob);
if (cob->ob == NULL) {
continue;
}
Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
base->local_collections_bits |= local_collections_uuid;
}

View File

@ -317,7 +317,8 @@ static void libblock_remap_data_preprocess(ID *id_owner,
*/
static void libblock_remap_data_postprocess_object_update(Main *bmain,
Object *old_ob,
Object *new_ob)
Object *new_ob,
const bool do_sync_collection)
{
if (new_ob == NULL) {
/* In case we unlinked old_ob (new_ob is NULL), the object has already
@ -331,7 +332,9 @@ static void libblock_remap_data_postprocess_object_update(Main *bmain,
BKE_collections_object_remove_duplicates(bmain);
}
BKE_main_collection_sync_remap(bmain);
if (do_sync_collection) {
BKE_main_collection_sync_remap(bmain);
}
if (old_ob == NULL) {
for (Object *ob = bmain->objects.first; ob != NULL; ob = ob->id.next) {
@ -567,7 +570,8 @@ static void libblock_remap_foreach_idpair_cb(ID *old_id, ID *new_id, void *user_
* Maybe we should do a per-ID callback for this instead? */
switch (GS(old_id->name)) {
case ID_OB:
libblock_remap_data_postprocess_object_update(bmain, (Object *)old_id, (Object *)new_id);
libblock_remap_data_postprocess_object_update(
bmain, (Object *)old_id, (Object *)new_id, true);
break;
case ID_GR:
libblock_remap_data_postprocess_collection_update(
@ -719,7 +723,7 @@ static void libblock_relink_foreach_idpair_cb(ID *old_id, ID *new_id, void *user
case ID_OB:
if (!is_object_update_processed) {
libblock_remap_data_postprocess_object_update(
bmain, (Object *)old_id, (Object *)new_id);
bmain, (Object *)old_id, (Object *)new_id, true);
is_object_update_processed = true;
}
break;
@ -781,11 +785,14 @@ void BKE_libblock_relink_multiple(Main *bmain,
(Collection *)id_iter :
((Scene *)id_iter)->master_collection;
/* No choice but to check whole objects once, and all children collections. */
libblock_remap_data_postprocess_collection_update(bmain, owner_collection, NULL, NULL);
if (!is_object_update_processed) {
libblock_remap_data_postprocess_object_update(bmain, NULL, NULL);
/* We only want to affect Object pointers here, not Collection ones, LayerCollections
* will be resynced as part of the call to
* `libblock_remap_data_postprocess_collection_update` below. */
libblock_remap_data_postprocess_object_update(bmain, NULL, NULL, false);
is_object_update_processed = true;
}
libblock_remap_data_postprocess_collection_update(bmain, owner_collection, NULL, NULL);
break;
}
default:

View File

@ -134,6 +134,14 @@ BLI_INLINE unsigned int clampis_uint(const unsigned int v,
return v < min ? min : (v > max ? max : v);
}
static ScanFillVert *scanfill_vert_add_v2_with_depth(ScanFillContext *sf_ctx,
const float co_xy[2],
const float co_z)
{
const float co[3] = {co_xy[0], co_xy[1], co_z};
return BLI_scanfill_vert_add(sf_ctx, co);
}
/* --------------------------------------------------------------------- */
/* local structs for mask rasterizing */
/* --------------------------------------------------------------------- */
@ -646,9 +654,6 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle,
ScanFillVert *sf_vert_prev;
unsigned int j;
float co[3];
co[2] = 0.0f;
sf_ctx.poly_nr++;
if (do_aspect_correct) {
@ -704,8 +709,7 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle,
spline, diff_feather_points, tot_diff_feather_points);
}
copy_v2_v2(co, diff_points[0]);
sf_vert_prev = BLI_scanfill_vert_add(&sf_ctx, co);
sf_vert_prev = scanfill_vert_add_v2_with_depth(&sf_ctx, diff_points[0], 0.0f);
sf_vert_prev->tmp.u = sf_vert_tot;
/* Absolute index of feather vert. */
@ -713,10 +717,8 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle,
sf_vert_tot++;
/* TODO: an alternate functions so we can avoid double vector copy! */
for (j = 1; j < tot_diff_point; j++) {
copy_v2_v2(co, diff_points[j]);
sf_vert = BLI_scanfill_vert_add(&sf_ctx, co);
sf_vert = scanfill_vert_add_v2_with_depth(&sf_ctx, diff_points[j], 0.0f);
sf_vert->tmp.u = sf_vert_tot;
sf_vert->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */
sf_vert_tot++;
@ -741,16 +743,12 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle,
}
if (diff_feather_points) {
float co_feather[3];
co_feather[2] = 1.0f;
BLI_assert(tot_diff_feather_points == tot_diff_point);
/* NOTE: only added for convenience, we don't in fact use these to scan-fill,
* only to create feather faces after scan-fill. */
for (j = 0; j < tot_diff_feather_points; j++) {
copy_v2_v2(co_feather, diff_feather_points[j]);
sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
sf_vert = scanfill_vert_add_v2_with_depth(&sf_ctx, diff_feather_points[j], 1.0f);
sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
sf_vert_tot++;
}
@ -762,15 +760,11 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle,
/* unfilled spline */
if (diff_feather_points) {
float co_diff[2];
float co_feather[3];
co_feather[2] = 1.0f;
if (spline->flag & MASK_SPLINE_NOINTERSECT) {
diff_feather_points_flip = MEM_mallocN(sizeof(float[2]) * tot_diff_feather_points,
"diff_feather_points_flip");
float co_diff[2];
for (j = 0; j < tot_diff_point; j++) {
sub_v2_v2v2(co_diff, diff_points[j], diff_feather_points[j]);
add_v2_v2v2(diff_feather_points_flip[j], diff_points[j], co_diff);
@ -792,29 +786,29 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle,
for (j = 0; j < tot_diff_point; j++) {
/* center vert */
copy_v2_v2(co, diff_points[j]);
sf_vert = BLI_scanfill_vert_add(&sf_ctx, co);
sf_vert = scanfill_vert_add_v2_with_depth(&sf_ctx, diff_points[j], 0.0f);
sf_vert->tmp.u = sf_vert_tot;
sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
sf_vert_tot++;
/* feather vert A */
copy_v2_v2(co_feather, diff_feather_points[j]);
sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
sf_vert = scanfill_vert_add_v2_with_depth(&sf_ctx, diff_feather_points[j], 1.0f);
sf_vert->tmp.u = sf_vert_tot;
sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
sf_vert_tot++;
/* feather vert B */
if (diff_feather_points_flip) {
copy_v2_v2(co_feather, diff_feather_points_flip[j]);
sf_vert = scanfill_vert_add_v2_with_depth(
&sf_ctx, diff_feather_points_flip[j], 1.0f);
}
else {
sub_v2_v2v2(co_diff, co, co_feather);
add_v2_v2v2(co_feather, co, co_diff);
float co_diff[2];
sub_v2_v2v2(co_diff, diff_points[j], diff_feather_points[j]);
add_v2_v2v2(co_diff, diff_points[j], co_diff);
sf_vert = scanfill_vert_add_v2_with_depth(&sf_ctx, co_diff, 1.0f);
}
sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
sf_vert->tmp.u = sf_vert_tot;
sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
sf_vert_tot++;
@ -857,9 +851,10 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle,
for (k = 1; k < vertex_total_cap; k++) {
const float angle = (float)k * (1.0f / (float)vertex_total_cap) * (float)M_PI;
float co_feather[2];
rotate_point_v2(co_feather, fp_turn, fp_cent, angle, asp_xy);
sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
sf_vert = scanfill_vert_add_v2_with_depth(&sf_ctx, co_feather, 1.0f);
sf_vert->tmp.u = sf_vert_tot;
sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
sf_vert_tot++;
@ -877,9 +872,10 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle,
for (k = 1; k < vertex_total_cap; k++) {
const float angle = (float)k * (1.0f / (float)vertex_total_cap) * (float)M_PI;
float co_feather[2];
rotate_point_v2(co_feather, fp_turn, fp_cent, -angle, asp_xy);
sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
sf_vert = scanfill_vert_add_v2_with_depth(&sf_ctx, co_feather, 1.0f);
sf_vert->tmp.u = sf_vert_tot;
sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
sf_vert_tot++;

View File

@ -221,7 +221,7 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
mesh->mface = nullptr;
mesh->totface = 0;
memset(&mesh->fdata, 0, sizeof(mesh->fdata));
memset(&mesh->runtime, 0, sizeof(mesh->runtime));
mesh->runtime = blender::dna::shallow_zero_initialize();
flayers = flayers_buff;
/* Do not store actual geometry data in case this is a library override ID. */
@ -332,7 +332,7 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id)
mesh->texflag &= ~ME_AUTOSPACE_EVALUATED;
mesh->edit_mesh = nullptr;
memset(&mesh->runtime, 0, sizeof(mesh->runtime));
mesh->runtime = blender::dna::shallow_zero_initialize();
BKE_mesh_runtime_init_data(mesh);
/* happens with old files */

View File

@ -700,7 +700,7 @@ void BKE_mesh_to_curve_nurblist(const Mesh *me, ListBase *nurblist, const int ed
VertLink *vl;
/* create new 'nurb' within the curve */
nu = MEM_cnew<Nurb>("MeshNurb");
nu = MEM_new<Nurb>("MeshNurb", blender::dna::shallow_zero_initialize());
nu->pntsu = totpoly;
nu->pntsv = 1;
@ -1446,8 +1446,7 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
/* mesh_src might depend on mesh_dst, so we need to do everything with a local copy */
/* TODO(Sybren): the above claim came from 2.7x derived-mesh code (DM_to_mesh);
* check whether it is still true with Mesh */
Mesh tmp;
memcpy(&tmp, mesh_dst, sizeof(tmp));
Mesh tmp = blender::dna::shallow_copy(*mesh_dst);
int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly;
bool did_shapekeys = false;
eCDAllocType alloctype = CD_DUPLICATE;

View File

@ -1352,7 +1352,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
if (need_lnors_dst) {
short(*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
/* Cache poly nors into a temp CDLayer. */
/* Cache loop normals into a temporary custom data layer. */
loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
const bool do_loop_nors_dst = (loop_nors_dst == NULL);
if (!loop_nors_dst) {

View File

@ -29,6 +29,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "BKE_attribute.h"
#include "BKE_bvhutils.h"
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
@ -814,30 +815,139 @@ void BKE_remesh_reproject_vertex_paint(Mesh *target, const Mesh *source)
BVHTreeFromMesh bvhtree = {nullptr};
BKE_bvhtree_from_mesh_get(&bvhtree, source, BVHTREE_FROM_VERTS, 2);
int tot_color_layer = CustomData_number_of_layers(&source->vdata, CD_PROP_COLOR);
int i = 0;
const CustomDataLayer *layer;
for (int layer_n = 0; layer_n < tot_color_layer; layer_n++) {
const char *layer_name = CustomData_get_layer_name(&source->vdata, CD_PROP_COLOR, layer_n);
CustomData_add_layer_named(
&target->vdata, CD_PROP_COLOR, CD_CALLOC, nullptr, target->totvert, layer_name);
MeshElemMap *source_lmap = nullptr;
int *source_lmap_mem = nullptr;
MeshElemMap *target_lmap = nullptr;
int *target_lmap_mem = nullptr;
MPropCol *target_color = (MPropCol *)CustomData_get_layer_n(
&target->vdata, CD_PROP_COLOR, layer_n);
while ((layer = BKE_id_attribute_from_index(
const_cast<ID *>(&source->id), i++, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL))) {
AttributeDomain domain = BKE_id_attribute_domain(&source->id, layer);
CustomData *target_cdata = domain == ATTR_DOMAIN_POINT ? &target->vdata : &target->ldata;
const CustomData *source_cdata = domain == ATTR_DOMAIN_POINT ? &source->vdata : &source->ldata;
/* Check attribute exists in target. */
int layer_i = CustomData_get_named_layer_index(target_cdata, layer->type, layer->name);
if (layer_i == -1) {
int elem_num = domain == ATTR_DOMAIN_POINT ? target->totvert : target->totloop;
CustomData_add_layer_named(
target_cdata, layer->type, CD_CALLOC, nullptr, elem_num, layer->name);
layer_i = CustomData_get_named_layer_index(target_cdata, layer->type, layer->name);
}
size_t data_size = CustomData_sizeof(layer->type);
void *target_data = target_cdata->layers[layer_i].data;
void *source_data = layer->data;
MVert *target_verts = (MVert *)CustomData_get_layer(&target->vdata, CD_MVERT);
const MPropCol *source_color = (const MPropCol *)CustomData_get_layer_n(
&source->vdata, CD_PROP_COLOR, layer_n);
for (int i = 0; i < target->totvert; i++) {
BVHTreeNearest nearest;
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
BLI_bvhtree_find_nearest(
bvhtree.tree, target_verts[i].co, &nearest, bvhtree.nearest_callback, &bvhtree);
if (nearest.index != -1) {
copy_v4_v4(target_color[i].color, source_color[nearest.index].color);
if (domain == ATTR_DOMAIN_POINT) {
for (int i = 0; i < target->totvert; i++) {
BVHTreeNearest nearest;
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
BLI_bvhtree_find_nearest(
bvhtree.tree, target_verts[i].co, &nearest, bvhtree.nearest_callback, &bvhtree);
if (nearest.index != -1) {
memcpy(POINTER_OFFSET(target_data, (size_t)i * data_size),
POINTER_OFFSET(source_data, (size_t)nearest.index * data_size),
data_size);
}
}
}
else {
/* Lazily init vertex -> loop maps. */
if (!source_lmap) {
const MPoly *source_polys = (MPoly *)CustomData_get_layer(&source->pdata, CD_MPOLY);
const MLoop *source_loops = (MLoop *)CustomData_get_layer(&source->ldata, CD_MLOOP);
const MPoly *target_polys = (MPoly *)CustomData_get_layer(&target->pdata, CD_MPOLY);
const MLoop *target_loops = (MLoop *)CustomData_get_layer(&target->ldata, CD_MLOOP);
BKE_mesh_vert_loop_map_create(&source_lmap,
&source_lmap_mem,
source_polys,
source_loops,
source->totvert,
source->totpoly,
source->totloop);
BKE_mesh_vert_loop_map_create(&target_lmap,
&target_lmap_mem,
target_polys,
target_loops,
target->totvert,
target->totpoly,
target->totloop);
}
for (int i = 0; i < target->totvert; i++) {
BVHTreeNearest nearest;
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
BLI_bvhtree_find_nearest(
bvhtree.tree, target_verts[i].co, &nearest, bvhtree.nearest_callback, &bvhtree);
if (nearest.index == -1) {
continue;
}
MeshElemMap *source_loops = source_lmap + nearest.index;
MeshElemMap *target_loops = target_lmap + i;
if (target_loops->count == 0 || source_loops->count == 0) {
continue;
}
/*
* Average color data for loops around the source vertex into
* the first target loop around the target vertex
*/
CustomData_interp(source_cdata,
target_cdata,
source_loops->indices,
nullptr,
nullptr,
source_loops->count,
target_loops->indices[0]);
void *elem = POINTER_OFFSET(target_data, (size_t)target_loops->indices[0] * data_size);
/* Copy to rest of target loops. */
for (int j = 1; j < target_loops->count; j++) {
memcpy(POINTER_OFFSET(target_data, (size_t)target_loops->indices[j] * data_size),
elem,
data_size);
}
}
}
}
MEM_SAFE_FREE(source_lmap);
MEM_SAFE_FREE(source_lmap_mem);
MEM_SAFE_FREE(target_lmap);
MEM_SAFE_FREE(target_lmap_mem);
free_bvhtree_from_mesh(&bvhtree);
/* Transfer active/render color attributes */
CustomDataLayer *active_layer = BKE_id_attributes_active_color_get(&source->id);
CustomDataLayer *render_layer = BKE_id_attributes_render_color_get(&source->id);
if (active_layer) {
BKE_id_attributes_active_color_set(
&target->id, BKE_id_attributes_color_find(&target->id, active_layer->name));
}
if (render_layer) {
BKE_id_attributes_render_color_set(
&target->id, BKE_id_attributes_color_find(&target->id, render_layer->name));
}
}
struct Mesh *BKE_mesh_remesh_voxel_fix_poles(const Mesh *mesh)

View File

@ -14,8 +14,7 @@
#include "DNA_object_types.h"
#include "BLI_math_geom.h"
#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_task.hh"
#include "BKE_bvhutils.h"
#include "BKE_lib_id.h"
@ -35,12 +34,12 @@
*/
static void mesh_runtime_init_mutexes(Mesh *mesh)
{
mesh->runtime.eval_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime eval_mutex");
BLI_mutex_init(mesh->runtime.eval_mutex);
mesh->runtime.normals_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime normals_mutex");
BLI_mutex_init(mesh->runtime.normals_mutex);
mesh->runtime.render_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime render_mutex");
BLI_mutex_init(mesh->runtime.render_mutex);
mesh->runtime.eval_mutex = MEM_new<ThreadMutex>("mesh runtime eval_mutex");
BLI_mutex_init(static_cast<ThreadMutex *>(mesh->runtime.eval_mutex));
mesh->runtime.normals_mutex = MEM_new<ThreadMutex>("mesh runtime normals_mutex");
BLI_mutex_init(static_cast<ThreadMutex *>(mesh->runtime.normals_mutex));
mesh->runtime.render_mutex = MEM_new<ThreadMutex>("mesh runtime render_mutex");
BLI_mutex_init(static_cast<ThreadMutex *>(mesh->runtime.render_mutex));
}
/**
@ -48,20 +47,20 @@ static void mesh_runtime_init_mutexes(Mesh *mesh)
*/
static void mesh_runtime_free_mutexes(Mesh *mesh)
{
if (mesh->runtime.eval_mutex != NULL) {
BLI_mutex_end(mesh->runtime.eval_mutex);
if (mesh->runtime.eval_mutex != nullptr) {
BLI_mutex_end(static_cast<ThreadMutex *>(mesh->runtime.eval_mutex));
MEM_freeN(mesh->runtime.eval_mutex);
mesh->runtime.eval_mutex = NULL;
mesh->runtime.eval_mutex = nullptr;
}
if (mesh->runtime.normals_mutex != NULL) {
BLI_mutex_end(mesh->runtime.normals_mutex);
if (mesh->runtime.normals_mutex != nullptr) {
BLI_mutex_end(static_cast<ThreadMutex *>(mesh->runtime.normals_mutex));
MEM_freeN(mesh->runtime.normals_mutex);
mesh->runtime.normals_mutex = NULL;
mesh->runtime.normals_mutex = nullptr;
}
if (mesh->runtime.render_mutex != NULL) {
BLI_mutex_end(mesh->runtime.render_mutex);
if (mesh->runtime.render_mutex != nullptr) {
BLI_mutex_end(static_cast<ThreadMutex *>(mesh->runtime.render_mutex));
MEM_freeN(mesh->runtime.render_mutex);
mesh->runtime.render_mutex = NULL;
mesh->runtime.render_mutex = nullptr;
}
}
@ -80,28 +79,28 @@ void BKE_mesh_runtime_reset_on_copy(Mesh *mesh, const int UNUSED(flag))
{
Mesh_Runtime *runtime = &mesh->runtime;
runtime->mesh_eval = NULL;
runtime->edit_data = NULL;
runtime->batch_cache = NULL;
runtime->subdiv_ccg = NULL;
memset(&runtime->looptris, 0, sizeof(runtime->looptris));
runtime->bvh_cache = NULL;
runtime->shrinkwrap_data = NULL;
runtime->mesh_eval = nullptr;
runtime->edit_data = nullptr;
runtime->batch_cache = nullptr;
runtime->subdiv_ccg = nullptr;
runtime->looptris = blender::dna::shallow_zero_initialize();
runtime->bvh_cache = nullptr;
runtime->shrinkwrap_data = nullptr;
runtime->vert_normals_dirty = true;
runtime->poly_normals_dirty = true;
runtime->vert_normals = NULL;
runtime->poly_normals = NULL;
runtime->vert_normals = nullptr;
runtime->poly_normals = nullptr;
mesh_runtime_init_mutexes(mesh);
}
void BKE_mesh_runtime_clear_cache(Mesh *mesh)
{
if (mesh->runtime.mesh_eval != NULL) {
mesh->runtime.mesh_eval->edit_mesh = NULL;
BKE_id_free(NULL, mesh->runtime.mesh_eval);
mesh->runtime.mesh_eval = NULL;
if (mesh->runtime.mesh_eval != nullptr) {
mesh->runtime.mesh_eval->edit_mesh = nullptr;
BKE_id_free(nullptr, mesh->runtime.mesh_eval);
mesh->runtime.mesh_eval = nullptr;
}
BKE_mesh_runtime_clear_geometry(mesh);
BKE_mesh_batch_cache_free(mesh);
@ -121,7 +120,7 @@ static void mesh_ensure_looptri_data(Mesh *mesh)
const uint totpoly = mesh->totpoly;
const int looptris_len = poly_to_tri_count(totpoly, mesh->totloop);
BLI_assert(mesh->runtime.looptris.array_wip == NULL);
BLI_assert(mesh->runtime.looptris.array_wip == nullptr);
SWAP(MLoopTri *, mesh->runtime.looptris.array, mesh->runtime.looptris.array_wip);
@ -133,9 +132,9 @@ static void mesh_ensure_looptri_data(Mesh *mesh)
}
if (totpoly) {
if (mesh->runtime.looptris.array_wip == NULL) {
mesh->runtime.looptris.array_wip = MEM_malloc_arrayN(
looptris_len, sizeof(*mesh->runtime.looptris.array_wip), __func__);
if (mesh->runtime.looptris.array_wip == nullptr) {
mesh->runtime.looptris.array_wip = static_cast<MLoopTri *>(
MEM_malloc_arrayN(looptris_len, sizeof(*mesh->runtime.looptris.array_wip), __func__));
mesh->runtime.looptris.len_alloc = looptris_len;
}
@ -146,7 +145,7 @@ static void mesh_ensure_looptri_data(Mesh *mesh)
void BKE_mesh_runtime_looptri_recalc(Mesh *mesh)
{
mesh_ensure_looptri_data(mesh);
BLI_assert(mesh->totpoly == 0 || mesh->runtime.looptris.array_wip != NULL);
BLI_assert(mesh->totpoly == 0 || mesh->runtime.looptris.array_wip != nullptr);
BKE_mesh_recalc_looptri(mesh->mloop,
mesh->mpoly,
@ -155,11 +154,11 @@ void BKE_mesh_runtime_looptri_recalc(Mesh *mesh)
mesh->totpoly,
mesh->runtime.looptris.array_wip);
BLI_assert(mesh->runtime.looptris.array == NULL);
BLI_assert(mesh->runtime.looptris.array == nullptr);
atomic_cas_ptr((void **)&mesh->runtime.looptris.array,
mesh->runtime.looptris.array,
mesh->runtime.looptris.array_wip);
mesh->runtime.looptris.array_wip = NULL;
mesh->runtime.looptris.array_wip = nullptr;
}
int BKE_mesh_runtime_looptri_len(const Mesh *mesh)
@ -170,12 +169,6 @@ int BKE_mesh_runtime_looptri_len(const Mesh *mesh)
return looptri_len;
}
static void mesh_runtime_looptri_recalc_isolated(void *userdata)
{
Mesh *mesh = userdata;
BKE_mesh_runtime_looptri_recalc(mesh);
}
const MLoopTri *BKE_mesh_runtime_looptri_ensure(const Mesh *mesh)
{
ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex;
@ -183,12 +176,13 @@ const MLoopTri *BKE_mesh_runtime_looptri_ensure(const Mesh *mesh)
MLoopTri *looptri = mesh->runtime.looptris.array;
if (looptri != NULL) {
if (looptri != nullptr) {
BLI_assert(BKE_mesh_runtime_looptri_len(mesh) == mesh->runtime.looptris.len);
}
else {
/* Must isolate multithreaded tasks while holding a mutex lock. */
BLI_task_isolate(mesh_runtime_looptri_recalc_isolated, (void *)mesh);
blender::threading::isolate_task(
[&]() { BKE_mesh_runtime_looptri_recalc(const_cast<Mesh *>(mesh)); });
looptri = mesh->runtime.looptris.array;
}
@ -211,18 +205,18 @@ void BKE_mesh_runtime_verttri_from_looptri(MVertTri *r_verttri,
bool BKE_mesh_runtime_ensure_edit_data(struct Mesh *mesh)
{
if (mesh->runtime.edit_data != NULL) {
if (mesh->runtime.edit_data != nullptr) {
return false;
}
mesh->runtime.edit_data = MEM_callocN(sizeof(EditMeshData), "EditMeshData");
mesh->runtime.edit_data = MEM_cnew<EditMeshData>(__func__);
return true;
}
bool BKE_mesh_runtime_reset_edit_data(Mesh *mesh)
{
EditMeshData *edit_data = mesh->runtime.edit_data;
if (edit_data == NULL) {
if (edit_data == nullptr) {
return false;
}
@ -236,13 +230,13 @@ bool BKE_mesh_runtime_reset_edit_data(Mesh *mesh)
bool BKE_mesh_runtime_clear_edit_data(Mesh *mesh)
{
if (mesh->runtime.edit_data == NULL) {
if (mesh->runtime.edit_data == nullptr) {
return false;
}
BKE_mesh_runtime_reset_edit_data(mesh);
MEM_freeN(mesh->runtime.edit_data);
mesh->runtime.edit_data = NULL;
mesh->runtime.edit_data = nullptr;
return true;
}
@ -251,13 +245,13 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
{
if (mesh->runtime.bvh_cache) {
bvhcache_free(mesh->runtime.bvh_cache);
mesh->runtime.bvh_cache = NULL;
mesh->runtime.bvh_cache = nullptr;
}
MEM_SAFE_FREE(mesh->runtime.looptris.array);
/* TODO(sergey): Does this really belong here? */
if (mesh->runtime.subdiv_ccg != NULL) {
if (mesh->runtime.subdiv_ccg != nullptr) {
BKE_subdiv_ccg_destroy(mesh->runtime.subdiv_ccg);
mesh->runtime.subdiv_ccg = NULL;
mesh->runtime.subdiv_ccg = nullptr;
}
BKE_shrinkwrap_discard_boundary_data(mesh);
}
@ -269,8 +263,8 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
* \{ */
/* Draw Engine */
void (*BKE_mesh_batch_cache_dirty_tag_cb)(Mesh *me, eMeshBatchDirtyMode mode) = NULL;
void (*BKE_mesh_batch_cache_free_cb)(Mesh *me) = NULL;
void (*BKE_mesh_batch_cache_dirty_tag_cb)(Mesh *me, eMeshBatchDirtyMode mode) = nullptr;
void (*BKE_mesh_batch_cache_free_cb)(Mesh *me) = nullptr;
void BKE_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode)
{

View File

@ -27,7 +27,7 @@
#include "BLI_ghash.h"
#include "BLI_math.h"
#include "BLI_task.h"
#include "BLI_task.hh"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@ -51,7 +51,7 @@ Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(BMEditMesh *em,
const float (*vert_coords)[3],
const Mesh *me_settings)
{
Mesh *me = BKE_id_new_nomain(ID_ME, NULL);
Mesh *me = static_cast<Mesh *>(BKE_id_new_nomain(ID_ME, nullptr));
BKE_mesh_copy_parameters_for_eval(me, me_settings);
BKE_mesh_runtime_ensure_edit_data(me);
@ -63,10 +63,10 @@ Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(BMEditMesh *em,
/* Use edit-mesh directly where possible. */
me->runtime.is_original = true;
me->edit_mesh = MEM_dupallocN(em);
me->edit_mesh = static_cast<BMEditMesh *>(MEM_dupallocN(em));
me->edit_mesh->is_shallow_copy = true;
/* Make sure, we crash if these are ever used. */
/* Make sure we crash if these are ever used. */
#ifdef DEBUG
me->totvert = INT_MAX;
me->totedge = INT_MAX;
@ -88,55 +88,7 @@ Mesh *BKE_mesh_wrapper_from_editmesh(BMEditMesh *em,
const CustomData_MeshMasks *cd_mask_extra,
const Mesh *me_settings)
{
return BKE_mesh_wrapper_from_editmesh_with_coords(em, cd_mask_extra, NULL, me_settings);
}
static void mesh_wrapper_ensure_mdata_isolated(void *userdata)
{
Mesh *me = userdata;
const eMeshWrapperType geom_type_orig = me->runtime.wrapper_type;
me->runtime.wrapper_type = ME_WRAPPER_TYPE_MDATA;
switch (geom_type_orig) {
case ME_WRAPPER_TYPE_MDATA:
case ME_WRAPPER_TYPE_SUBD: {
break; /* Quiet warning. */
}
case ME_WRAPPER_TYPE_BMESH: {
me->totvert = 0;
me->totedge = 0;
me->totpoly = 0;
me->totloop = 0;
BLI_assert(me->edit_mesh != NULL);
BLI_assert(me->runtime.edit_data != NULL);
BMEditMesh *em = me->edit_mesh;
BM_mesh_bm_to_me_for_eval(em->bm, me, &me->runtime.cd_mask_extra);
/* Adding original index layers assumes that all BMesh mesh wrappers are created from
* original edit mode meshes (the only case where adding original indices makes sense).
* If that assumption is broken, the layers might be incorrect in that they might not
* actually be "original".
*
* There is also a performance aspect, where this also assumes that original indices are
* always needed when converting an edit mesh to a mesh. That might be wrong, but it's not
* harmful. */
BKE_mesh_ensure_default_orig_index_customdata(me);
EditMeshData *edit_data = me->runtime.edit_data;
if (edit_data->vertexCos) {
BKE_mesh_vert_coords_apply(me, edit_data->vertexCos);
me->runtime.is_original = false;
}
break;
}
}
if (me->runtime.wrapper_type_finalize) {
BKE_mesh_wrapper_deferred_finalize(me, &me->runtime.cd_mask_extra);
}
return BKE_mesh_wrapper_from_editmesh_with_coords(em, cd_mask_extra, nullptr, me_settings);
}
void BKE_mesh_wrapper_ensure_mdata(Mesh *me)
@ -150,7 +102,51 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *me)
}
/* Must isolate multithreaded tasks while holding a mutex lock. */
BLI_task_isolate(mesh_wrapper_ensure_mdata_isolated, me);
blender::threading::isolate_task([&]() {
const eMeshWrapperType geom_type_orig = static_cast<eMeshWrapperType>(
me->runtime.wrapper_type);
me->runtime.wrapper_type = ME_WRAPPER_TYPE_MDATA;
switch (geom_type_orig) {
case ME_WRAPPER_TYPE_MDATA:
case ME_WRAPPER_TYPE_SUBD: {
break; /* Quiet warning. */
}
case ME_WRAPPER_TYPE_BMESH: {
me->totvert = 0;
me->totedge = 0;
me->totpoly = 0;
me->totloop = 0;
BLI_assert(me->edit_mesh != nullptr);
BLI_assert(me->runtime.edit_data != nullptr);
BMEditMesh *em = me->edit_mesh;
BM_mesh_bm_to_me_for_eval(em->bm, me, &me->runtime.cd_mask_extra);
/* Adding original index layers assumes that all BMesh mesh wrappers are created from
* original edit mode meshes (the only case where adding original indices makes sense).
* If that assumption is broken, the layers might be incorrect in that they might not
* actually be "original".
*
* There is also a performance aspect, where this also assumes that original indices are
* always needed when converting an edit mesh to a mesh. That might be wrong, but it's not
* harmful. */
BKE_mesh_ensure_default_orig_index_customdata(me);
EditMeshData *edit_data = me->runtime.edit_data;
if (edit_data->vertexCos) {
BKE_mesh_vert_coords_apply(me, edit_data->vertexCos);
me->runtime.is_original = false;
}
break;
}
}
if (me->runtime.wrapper_type_finalize) {
BKE_mesh_wrapper_deferred_finalize(me, &me->runtime.cd_mask_extra);
}
});
BLI_mutex_unlock(mesh_eval_mutex);
}
@ -181,7 +177,7 @@ void BKE_mesh_wrapper_vert_coords_copy(const Mesh *me,
BMesh *bm = me->edit_mesh->bm;
BLI_assert(vert_coords_len <= bm->totvert);
EditMeshData *edit_data = me->runtime.edit_data;
if (edit_data->vertexCos != NULL) {
if (edit_data->vertexCos != nullptr) {
for (int i = 0; i < vert_coords_len; i++) {
copy_v3_v3(vert_coords[i], edit_data->vertexCos[i]);
}
@ -219,7 +215,7 @@ void BKE_mesh_wrapper_vert_coords_copy_with_mat4(const Mesh *me,
BMesh *bm = me->edit_mesh->bm;
BLI_assert(vert_coords_len == bm->totvert);
EditMeshData *edit_data = me->runtime.edit_data;
if (edit_data->vertexCos != NULL) {
if (edit_data->vertexCos != nullptr) {
for (int i = 0; i < vert_coords_len; i++) {
mul_v3_m4v3(vert_coords[i], mat, edit_data->vertexCos[i]);
}
@ -340,7 +336,7 @@ static Mesh *mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &subdiv_settings, me, false);
if (subdiv == NULL) {
if (subdiv == nullptr) {
/* Happens on bad topology, but also on empty input mesh. */
return me;
}
@ -352,8 +348,8 @@ static Mesh *mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
}
if (subdiv_mesh != me) {
if (me->runtime.mesh_eval != NULL) {
BKE_id_free(NULL, me->runtime.mesh_eval);
if (me->runtime.mesh_eval != nullptr) {
BKE_id_free(nullptr, me->runtime.mesh_eval);
}
me->runtime.mesh_eval = subdiv_mesh;
me->runtime.wrapper_type = ME_WRAPPER_TYPE_SUBD;
@ -362,20 +358,6 @@ static Mesh *mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
return me->runtime.mesh_eval;
}
typedef struct SubdivisionWrapperIsolatedTaskData {
const Object *ob;
Mesh *me;
Mesh *result;
} SubdivisionWrapperIsolatedTaskData;
static void mesh_wrapper_ensure_subdivision_isolated(void *userdata)
{
SubdivisionWrapperIsolatedTaskData *task_data = (SubdivisionWrapperIsolatedTaskData *)userdata;
const Object *ob = task_data->ob;
Mesh *me = task_data->me;
task_data->result = mesh_wrapper_ensure_subdivision(ob, me);
}
Mesh *BKE_mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
{
ThreadMutex *mesh_eval_mutex = (ThreadMutex *)me->runtime.eval_mutex;
@ -386,15 +368,13 @@ Mesh *BKE_mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
return me->runtime.mesh_eval;
}
SubdivisionWrapperIsolatedTaskData task_data;
task_data.ob = ob;
task_data.me = me;
Mesh *result;
/* Must isolate multithreaded tasks while holding a mutex lock. */
BLI_task_isolate(mesh_wrapper_ensure_subdivision_isolated, &task_data);
blender::threading::isolate_task([&]() { result = mesh_wrapper_ensure_subdivision(ob, me); });
BLI_mutex_unlock(mesh_eval_mutex);
return task_data.result;
return result;
}
/** \} */

View File

@ -1977,8 +1977,11 @@ bool BKE_nla_tweakmode_enter(AnimData *adt)
/* go over all the tracks after AND INCLUDING the active one, tagging them as being disabled
* - the active track needs to also be tagged, otherwise, it'll overlap with the tweaks going on
*/
for (nlt = activeTrack; nlt; nlt = nlt->next) {
nlt->flag |= NLATRACK_DISABLED;
activeTrack->flag |= NLATRACK_DISABLED;
if ((adt->flag & ADT_NLA_EVAL_UPPER_TRACKS) == 0) {
for (nlt = activeTrack->next; nlt; nlt = nlt->next) {
nlt->flag |= NLATRACK_DISABLED;
}
}
/* handle AnimData level changes:

View File

@ -719,7 +719,7 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
}
case SH_NODE_TEX_POINTDENSITY: {
NodeShaderTexPointDensity *npd = (NodeShaderTexPointDensity *)node->storage;
memset(&npd->pd, 0, sizeof(npd->pd));
npd->pd = blender::dna::shallow_zero_initialize();
break;
}
case SH_NODE_TEX_IMAGE: {

View File

@ -3096,12 +3096,12 @@ void BKE_object_matrix_local_get(struct Object *ob, float r_mat[4][4])
static bool ob_parcurve(Object *ob, Object *par, float r_mat[4][4])
{
Curve *cu = (Curve *)par->data;
float vec[4], dir[3], quat[4], radius, ctime;
float vec[4], quat[4], radius, ctime;
/* NOTE: Curve cache is supposed to be evaluated here already, however there
* are cases where we can not guarantee that. This includes, for example,
* dependency cycles. We can't correct anything from here, since that would
* cause a threading conflicts.
* cause threading conflicts.
*
* TODO(sergey): Some of the legit looking cases like T56619 need to be
* looked into, and maybe curve cache (and other dependencies) are to be
@ -3134,7 +3134,7 @@ static bool ob_parcurve(Object *ob, Object *par, float r_mat[4][4])
/* vec: 4 items! */
if (BKE_where_on_path(
par, ctime, vec, dir, (cu->flag & CU_FOLLOW) ? quat : nullptr, &radius, nullptr)) {
par, ctime, vec, nullptr, (cu->flag & CU_FOLLOW) ? quat : nullptr, &radius, nullptr)) {
if (cu->flag & CU_FOLLOW) {
quat_apply_track(quat, ob->trackflag, ob->upflag);
normalize_qt(quat);
@ -3567,6 +3567,55 @@ void BKE_object_apply_mat4(Object *ob,
BKE_object_apply_mat4_ex(ob, mat, use_parent ? ob->parent : nullptr, ob->parentinv, use_compat);
}
void BKE_object_apply_parent_inverse(struct Object *ob)
{
/*
* Use parent's world transform as the child's origin.
*
* Let:
* local = identity
* world = orthonormalized(parent)
*
* Then:
* world = parent @ parentinv @ local
* inv(parent) @ world = parentinv
* parentinv = inv(parent) @ world
*
* NOTE: If ob->obmat has shear, then this `parentinv` is insufficient because
* parent @ parentinv => shearless result
*
* Thus, local will have shear which cannot be decomposed into TRS:
* local = inv(parent @ parentinv) @ world
*
* This is currently not supported for consistency in the handling of shear during the other
* parenting ops: Parent (Keep Transform), Clear [Parent] and Keep Transform.
*/
float par_locrot[4][4], par_imat[4][4];
BKE_object_get_parent_matrix(ob, ob->parent, par_locrot);
invert_m4_m4(par_imat, par_locrot);
orthogonalize_m4_stable(par_locrot, 0, true);
mul_m4_m4m4(ob->parentinv, par_imat, par_locrot);
/* Now, preserve `world` given the new `parentinv`.
*
* world = parent @ parentinv @ local
* inv(parent) @ world = parentinv @ local
* inv(parentinv) @ inv(parent) @ world = local
*
* local = inv(parentinv) @ inv(parent) @ world
*/
float ob_local[4][4];
copy_m4_m4(ob_local, ob->parentinv);
invert_m4(ob_local);
mul_m4_m4_post(ob_local, par_imat);
mul_m4_m4_post(ob_local, ob->obmat);
/* Send use_compat=False so the rotation is predictable. */
BKE_object_apply_mat4(ob, ob_local, false, false);
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -0,0 +1,90 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_compiler_compat.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_scene_types.h"
#include "BKE_customdata.h"
#include "BKE_material.h"
#include "BKE_paint.h"
namespace blender::bke::paint::canvas {
static TexPaintSlot *get_active_slot(Object *ob)
{
Material *mat = BKE_object_material_get(ob, ob->actcol);
if (mat == nullptr) {
return nullptr;
}
if (mat->texpaintslot == nullptr) {
return nullptr;
}
if (mat->paint_active_slot >= mat->tot_slots) {
return nullptr;
}
TexPaintSlot *slot = &mat->texpaintslot[mat->paint_active_slot];
return slot;
}
} // namespace blender::bke::paint::canvas
extern "C" {
using namespace blender::bke::paint::canvas;
Image *BKE_paint_canvas_image_get(const struct PaintModeSettings *settings, struct Object *ob)
{
switch (settings->canvas_source) {
case PAINT_CANVAS_SOURCE_COLOR_ATTRIBUTE:
return nullptr;
case PAINT_CANVAS_SOURCE_IMAGE:
return settings->canvas_image;
case PAINT_CANVAS_SOURCE_MATERIAL: {
TexPaintSlot *slot = get_active_slot(ob);
if (slot == nullptr) {
break;
}
return slot->ima;
}
}
return nullptr;
}
int BKE_paint_canvas_uvmap_layer_index_get(const struct PaintModeSettings *settings,
struct Object *ob)
{
switch (settings->canvas_source) {
case PAINT_CANVAS_SOURCE_COLOR_ATTRIBUTE:
return -1;
case PAINT_CANVAS_SOURCE_IMAGE: {
/* Use active uv map of the object. */
if (ob->type != OB_MESH) {
return -1;
}
const Mesh *mesh = static_cast<Mesh *>(ob->data);
return CustomData_get_active_layer_index(&mesh->ldata, CD_MLOOPUV);
}
case PAINT_CANVAS_SOURCE_MATERIAL: {
/* Use uv map of the canvas. */
TexPaintSlot *slot = get_active_slot(ob);
if (slot == nullptr) {
break;
}
if (ob->type != OB_MESH) {
return -1;
}
if (slot->uvname == nullptr) {
return -1;
}
const Mesh *mesh = static_cast<Mesh *>(ob->data);
return CustomData_get_named_layer_index(&mesh->ldata, CD_MLOOPUV, slot->uvname);
}
}
return -1;
}
}

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