Merge remote-tracking branch 'origin/master' into sculpt-dev
This commit is contained in:
commit
ecbf681e31
|
@ -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()
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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':
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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__);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -40,7 +40,7 @@ size_t count_utf_8_from_16(const wchar_t *string16)
|
|||
}
|
||||
else {
|
||||
if (u < 0xE000) {
|
||||
/*illegal*/;
|
||||
/* Illegal. */
|
||||
}
|
||||
else {
|
||||
count += 3;
|
||||
|
|
|
@ -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
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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
|
@ -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'},
|
||||
|
|
|
@ -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'}),
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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).
|
||||
*
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()));
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 ¤t_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
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
{
|
|
@ -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;
|
||||
}
|
||||
|
||||
/** \} */
|
|
@ -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:
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue