BLI: new bit span data structure #104671
|
@ -524,7 +524,7 @@ endif()
|
|||
if(NOT APPLE)
|
||||
option(WITH_CYCLES_DEVICE_HIP "Enable Cycles AMD HIP support" ON)
|
||||
option(WITH_CYCLES_HIP_BINARIES "Build Cycles AMD HIP binaries" OFF)
|
||||
set(CYCLES_HIP_BINARIES_ARCH gfx1010 gfx1011 gfx1012 gfx1030 gfx1031 gfx1032 gfx1034 gfx1035 gfx1100 gfx1101 gfx1102 CACHE STRING "AMD HIP architectures to build binaries for")
|
||||
set(CYCLES_HIP_BINARIES_ARCH gfx900 gfx906 gfx90c gfx902 gfx1010 gfx1011 gfx1012 gfx1030 gfx1031 gfx1032 gfx1034 gfx1035 gfx1100 gfx1101 gfx1102 CACHE STRING "AMD HIP architectures to build binaries for")
|
||||
mark_as_advanced(WITH_CYCLES_DEVICE_HIP)
|
||||
mark_as_advanced(CYCLES_HIP_BINARIES_ARCH)
|
||||
endif()
|
||||
|
@ -625,8 +625,10 @@ mark_as_advanced(
|
|||
|
||||
# Vulkan
|
||||
option(WITH_VULKAN_BACKEND "Enable Vulkan as graphics backend (only for development)" OFF)
|
||||
option(WITH_VULKAN_GUARDEDALLOC "Use guardedalloc for host allocations done inside Vulkan (development option)" OFF)
|
||||
mark_as_advanced(
|
||||
WITH_VULKAN_BACKEND
|
||||
WITH_VULKAN_GUARDEDALLOC
|
||||
)
|
||||
|
||||
# Metal
|
||||
|
|
|
@ -299,7 +299,11 @@ else
|
|||
ifneq ("$(wildcard $(DEPS_BUILD_DIR)/build.ninja)","")
|
||||
DEPS_BUILD_COMMAND:=ninja
|
||||
else
|
||||
DEPS_BUILD_COMMAND:=make -s
|
||||
ifeq ($(OS), Darwin)
|
||||
DEPS_BUILD_COMMAND:=make -s
|
||||
else
|
||||
DEPS_BUILD_COMMAND:="$(BLENDER_DIR)/build_files/build_environment/linux/make_deps_wrapper.sh" -s
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
|
@ -398,7 +402,7 @@ endif
|
|||
|
||||
deps: .FORCE
|
||||
@echo
|
||||
@echo Configuring dependencies in \"$(DEPS_BUILD_DIR)\"
|
||||
@echo Configuring dependencies in \"$(DEPS_BUILD_DIR)\", install to \"$(DEPS_INSTALL_DIR)\"
|
||||
|
||||
@cmake -H"$(DEPS_SOURCE_DIR)" \
|
||||
-B"$(DEPS_BUILD_DIR)" \
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
# This script ensures:
|
||||
# - One dependency is built at a time.
|
||||
# - That dependency uses all available cores.
|
||||
#
|
||||
# Without this, simply calling `make -j$(nproc)` from the `${CMAKE_BUILD_DIR}/deps/`
|
||||
# directory will build many projects at once.
|
||||
#
|
||||
# This is undesirable for the following reasons:
|
||||
#
|
||||
# - The output from projects is mixed together,
|
||||
# making it difficult to track down the cause of a build failure.
|
||||
#
|
||||
# - Larger dependencies such as LLVM can bottleneck the build process,
|
||||
# making it necessary to cancel the build and manually run build commands in each directory.
|
||||
#
|
||||
# - Building many projects at once means canceling (Control-C) can lead to the build being in an undefined state.
|
||||
# It's possible canceling happens as a patch is being applied or files are being copied.
|
||||
# (steps that aren't part of the compilation process where it's typically safe to cancel).
|
||||
|
||||
if [[ -z "$MY_MAKE_CALL_LEVEL" ]]; then
|
||||
export MY_MAKE_CALL_LEVEL=0
|
||||
export MY_MAKEFLAGS=$MAKEFLAGS
|
||||
|
||||
# Extract the jobs argument (`-jN`, `-j N`, `--jobs=N`).
|
||||
add_next=0
|
||||
for i in "$@"; do
|
||||
case $i in
|
||||
-j*)
|
||||
export MY_JOBS_ARG=$i
|
||||
if [ "$MY_JOBS_ARG" = "-j" ]; then
|
||||
add_next=1
|
||||
fi
|
||||
;;
|
||||
--jobs=*)
|
||||
shift # past argument=value
|
||||
MY_JOBS_ARG=$i
|
||||
;;
|
||||
*)
|
||||
if (( add_next == 1 )); then
|
||||
MY_JOBS_ARG="$MY_JOBS_ARG $i"
|
||||
add_next=0
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
unset i add_next
|
||||
|
||||
if [[ -z "$MY_JOBS_ARG" ]]; then
|
||||
MY_JOBS_ARG="-j$(nproc)"
|
||||
fi
|
||||
export MY_JOBS_ARG
|
||||
# Support user defined `MAKEFLAGS`.
|
||||
export MAKEFLAGS="$MY_MAKEFLAGS -j1"
|
||||
else
|
||||
export MY_MAKE_CALL_LEVEL=$(( MY_MAKE_CALL_LEVEL + 1 ))
|
||||
if (( MY_MAKE_CALL_LEVEL == 1 )); then
|
||||
# Important to set jobs to 1, otherwise user defined jobs argument is used.
|
||||
export MAKEFLAGS="$MY_MAKEFLAGS -j1"
|
||||
elif (( MY_MAKE_CALL_LEVEL == 2 )); then
|
||||
# This is the level used by each sub-project.
|
||||
export MAKEFLAGS="$MY_MAKEFLAGS $MY_JOBS_ARG"
|
||||
fi
|
||||
# Else leave `MY_MAKEFLAGS` flags as-is, avoids setting a high number of jobs on recursive
|
||||
# calls (which may easily run out of memory). Let the job-server handle the rest.
|
||||
fi
|
||||
|
||||
# Useful for troubleshooting the wrapper.
|
||||
# echo "Call level: $MY_MAKE_CALL_LEVEL, args=$@".
|
||||
|
||||
# Call actual make but ensure recursive calls run via this script.
|
||||
exec make MAKE="$0" "$@"
|
|
@ -295,7 +295,7 @@ unset(MATERIALX_LIB_FOLDER_EXISTS)
|
|||
if(NOT MSVC_CLANG AND # Available with MSVC 15.7+ but not for CLANG.
|
||||
NOT WITH_WINDOWS_SCCACHE AND # And not when sccache is enabled
|
||||
NOT VS_CLANG_TIDY) # Clang-tidy does not like these options
|
||||
add_compile_options(/experimental:external /external:templates- /external:I "${LIBDIR}" /external:W0)
|
||||
add_compile_options(/experimental:external /external:I "${LIBDIR}" /external:W0)
|
||||
endif()
|
||||
|
||||
# Add each of our libraries to our cmake_prefix_path so find_package() could work
|
||||
|
|
|
@ -487,7 +487,7 @@ BLENDER_VERSION_DOTS = "%d.%d" % (bpy.app.version[0], bpy.app.version[1])
|
|||
if BLENDER_REVISION != "Unknown":
|
||||
# SHA1 Git hash
|
||||
BLENDER_VERSION_HASH = BLENDER_REVISION
|
||||
BLENDER_VERSION_HASH_HTML_LINK = "<a href=https://developer.blender.org/rB%s>%s</a>" % (
|
||||
BLENDER_VERSION_HASH_HTML_LINK = "<a href=https://projects.blender.org/blender/blender/commit/%s>%s</a>" % (
|
||||
BLENDER_VERSION_HASH, BLENDER_VERSION_HASH,
|
||||
)
|
||||
BLENDER_VERSION_DATE = time.strftime("%d/%m/%Y", time.localtime(BLENDER_REVISION_TIMESTAMP))
|
||||
|
@ -647,7 +647,7 @@ def undocumented_message(module_name, type_name, identifier):
|
|||
module_name, type_name, identifier,
|
||||
)
|
||||
|
||||
return "Undocumented, consider `contributing <https://developer.blender.org/T51061>`__."
|
||||
return "Undocumented, consider `contributing <https://developer.blender.org/>`__."
|
||||
|
||||
|
||||
def range_str(val):
|
||||
|
|
|
@ -1679,12 +1679,12 @@ class CyclesPreferences(bpy.types.AddonPreferences):
|
|||
import sys
|
||||
if sys.platform[:3] == "win":
|
||||
driver_version = "21.Q4"
|
||||
col.label(text="Requires AMD GPU with RDNA architecture", icon='BLANK1')
|
||||
col.label(text="Requires AMD GPU with Vega or RDNA architecture", icon='BLANK1')
|
||||
col.label(text=iface_("and AMD Radeon Pro %s driver or newer") % driver_version,
|
||||
icon='BLANK1', translate=False)
|
||||
elif sys.platform.startswith("linux"):
|
||||
driver_version = "22.10"
|
||||
col.label(text="Requires AMD GPU with RDNA architecture", icon='BLANK1')
|
||||
col.label(text="Requires AMD GPU with Vega or RDNA architecture", icon='BLANK1')
|
||||
col.label(text=iface_("and AMD driver version %s or newer") % driver_version, icon='BLANK1',
|
||||
translate=False)
|
||||
elif device_type == 'ONEAPI':
|
||||
|
|
|
@ -105,11 +105,12 @@ GPUShader *BlenderFallbackDisplayShader::bind(int width, int height)
|
|||
|
||||
/* Bind shader now to enable uniform assignment. */
|
||||
GPU_shader_bind(shader_program_);
|
||||
GPU_shader_uniform_int(shader_program_, image_texture_location_, 0);
|
||||
int slot = 0;
|
||||
GPU_shader_uniform_int_ex(shader_program_, image_texture_location_, 1, 1, &slot);
|
||||
float size[2];
|
||||
size[0] = width;
|
||||
size[1] = height;
|
||||
GPU_shader_uniform_vector(shader_program_, fullscreen_location_, 2, 1, size);
|
||||
GPU_shader_uniform_float_ex(shader_program_, fullscreen_location_, 2, 1, size);
|
||||
return shader_program_;
|
||||
}
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ void python_thread_state_restore(void **python_thread_state)
|
|||
*python_thread_state = NULL;
|
||||
}
|
||||
|
||||
static const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
|
||||
static const char *PyC_UnicodeAsBytes(PyObject *py_str, PyObject **coerce)
|
||||
{
|
||||
const char *result = PyUnicode_AsUTF8(py_str);
|
||||
if (result) {
|
||||
|
@ -131,8 +131,8 @@ static PyObject *init_func(PyObject * /*self*/, PyObject *args)
|
|||
}
|
||||
|
||||
PyObject *path_coerce = nullptr, *user_path_coerce = nullptr;
|
||||
path_init(PyC_UnicodeAsByte(path, &path_coerce),
|
||||
PyC_UnicodeAsByte(user_path, &user_path_coerce));
|
||||
path_init(PyC_UnicodeAsBytes(path, &path_coerce),
|
||||
PyC_UnicodeAsBytes(user_path, &user_path_coerce));
|
||||
Py_XDECREF(path_coerce);
|
||||
Py_XDECREF(user_path_coerce);
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ static inline bool hipSupportsDevice(const int hipDevId)
|
|||
hipDeviceGetAttribute(&major, hipDeviceAttributeComputeCapabilityMajor, hipDevId);
|
||||
hipDeviceGetAttribute(&minor, hipDeviceAttributeComputeCapabilityMinor, hipDevId);
|
||||
|
||||
return (major >= 10);
|
||||
return (major >= 9);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
|
|
@ -886,7 +886,7 @@ int RenderScheduler::get_num_samples_during_navigation(int resolution_divider) c
|
|||
{
|
||||
/* Special trick for fast navigation: schedule multiple samples during fast navigation
|
||||
* (which will prefer to use lower resolution to keep up with refresh rate). This gives more
|
||||
* usable visual feedback for artists. There are a couple of tricks though. */
|
||||
* usable visual feedback for artists. */
|
||||
|
||||
if (is_denoise_active_during_update()) {
|
||||
/* When denoising is used during navigation prefer using a higher resolution with less samples
|
||||
|
@ -896,25 +896,12 @@ int RenderScheduler::get_num_samples_during_navigation(int resolution_divider) c
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (resolution_divider <= pixel_size_) {
|
||||
/* When resolution divider is at or below pixel size, schedule one sample. This doesn't effect
|
||||
* the sample count at this resolution division, but instead assists in the calculation of
|
||||
* the resolution divider. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (resolution_divider == pixel_size_ * 2) {
|
||||
/* When resolution divider is the previous step to the final resolution, schedule two samples.
|
||||
* This is so that rendering on lower resolution does not exceed time that it takes to render
|
||||
* first sample at the full resolution. */
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* Always render 4 samples, even if scene is configured for less.
|
||||
* The idea here is to have enough information on the screen. Resolution divider of 2 allows us
|
||||
* to have 4 time extra samples, so overall worst case timing is the same as the final resolution
|
||||
* at one sample. */
|
||||
return 4;
|
||||
/* Schedule samples equal to the resolution divider up to a maximum of 4.
|
||||
* The idea is to have enough information on the screen by increasing the sample count as the
|
||||
* resolution is decreased. */
|
||||
/* NOTE: Changing this formula will change the formula in
|
||||
* `RenderScheduler::calculate_resolution_divider_for_time()`. */
|
||||
return min(max(1, resolution_divider / pixel_size_), 4);
|
||||
}
|
||||
|
||||
bool RenderScheduler::work_need_adaptive_filter() const
|
||||
|
@ -1100,9 +1087,10 @@ void RenderScheduler::update_start_resolution_divider()
|
|||
/* TODO(sergey): Need to add hysteresis to avoid resolution divider bouncing around when actual
|
||||
* render time is somewhere on a boundary between two resolutions. */
|
||||
|
||||
/* Never increase resolution to higher than the pixel size (which is possible if the scene is
|
||||
* simple and compute device is fast). */
|
||||
start_resolution_divider_ = max(resolution_divider_for_update, pixel_size_);
|
||||
/* Don't let resolution drop below the desired one. It's better to be slow than provide an
|
||||
* unreadable viewport render. */
|
||||
start_resolution_divider_ = min(resolution_divider_for_update,
|
||||
default_start_resolution_divider_);
|
||||
|
||||
VLOG_WORK << "Calculated resolution divider is " << start_resolution_divider_;
|
||||
}
|
||||
|
@ -1187,24 +1175,24 @@ void RenderScheduler::check_time_limit_reached()
|
|||
|
||||
int RenderScheduler::calculate_resolution_divider_for_time(double desired_time, double actual_time)
|
||||
{
|
||||
/* TODO(sergey): There should a non-iterative analytical formula here. */
|
||||
const double ratio_between_times = actual_time / desired_time;
|
||||
|
||||
int resolution_divider = 1;
|
||||
/* We can pass `ratio_between_times` to `get_num_samples_during_navigation()` to get our
|
||||
* navigation samples because the equation for calculating the resolution divider is as follows:
|
||||
* `actual_time / desired_time = sqr(resolution_divider) / sample_count`.
|
||||
* While `resolution_divider` is less than or equal to 4, `resolution_divider = sample_count`
|
||||
* (This relationship is determined in `get_num_samples_during_navigation()`). With some
|
||||
* substitution we end up with `actual_time / desired_time = resolution_divider` while the
|
||||
* resolution divider is less than or equal to 4. Once the resolution divider increases above 4,
|
||||
* the relationship of `actual_time / desired_time = resolution_divider` is no longer true,
|
||||
* however the sample count retrieved from `get_num_samples_during_navigation()` is still
|
||||
* accurate if we continue using this assumption. It should be noted that the interaction between
|
||||
* `pixel_size`, sample count, and resolution divider are automatically accounted for and that's
|
||||
* why `pixel_size` isn't included in any of the equations. */
|
||||
const int navigation_samples = get_num_samples_during_navigation(
|
||||
ceil_to_int(ratio_between_times));
|
||||
|
||||
/* This algorithm iterates through resolution dividers until a divider is found that achieves
|
||||
* the desired render time. A limit of default_start_resolution_divider_ is put in place as the
|
||||
* maximum resolution divider to avoid an unreadable viewport due to a low resolution.
|
||||
* pre_resolution_division_samples and post_resolution_division_samples are used in this
|
||||
* calculation to better predict the performance impact of changing resolution divisions as
|
||||
* the sample count can also change between resolution divisions. */
|
||||
while (actual_time > desired_time && resolution_divider < default_start_resolution_divider_) {
|
||||
int pre_resolution_division_samples = get_num_samples_during_navigation(resolution_divider);
|
||||
resolution_divider = resolution_divider * 2;
|
||||
int post_resolution_division_samples = get_num_samples_during_navigation(resolution_divider);
|
||||
actual_time /= 4.0 * pre_resolution_division_samples / post_resolution_division_samples;
|
||||
}
|
||||
|
||||
return resolution_divider;
|
||||
return ceil_to_int(sqrt(navigation_samples * ratio_between_times));
|
||||
}
|
||||
|
||||
int calculate_resolution_divider_for_resolution(int width, int height, int resolution)
|
||||
|
|
|
@ -412,11 +412,12 @@ if(WITH_CYCLES_CUDA_BINARIES)
|
|||
# warn for other versions
|
||||
if((CUDA_VERSION STREQUAL "101") OR
|
||||
(CUDA_VERSION STREQUAL "102") OR
|
||||
(CUDA_VERSION_MAJOR STREQUAL "11"))
|
||||
(CUDA_VERSION_MAJOR STREQUAL "11") OR
|
||||
(CUDA_VERSION_MAJOR STREQUAL "12"))
|
||||
else()
|
||||
message(WARNING
|
||||
"CUDA version ${CUDA_VERSION_MAJOR}.${CUDA_VERSION_MINOR} detected, "
|
||||
"build may succeed but only CUDA 11, 10.2 and 10.1 have been tested")
|
||||
"build may succeed but only CUDA 12, 11, 10.2 and 10.1 have been tested")
|
||||
endif()
|
||||
|
||||
# build for each arch
|
||||
|
@ -514,6 +515,16 @@ if(WITH_CYCLES_CUDA_BINARIES)
|
|||
else()
|
||||
message(STATUS "CUDA binaries for ${arch} require CUDA 10 or earlier, skipped.")
|
||||
endif()
|
||||
elseif(${arch} MATCHES ".*_3.")
|
||||
if(DEFINED CUDA11_NVCC_EXECUTABLE)
|
||||
set(cuda_nvcc_executable ${CUDA11_NVCC_EXECUTABLE})
|
||||
set(cuda_toolkit_root_dir ${CUDA11_TOOLKIT_ROOT_DIR})
|
||||
elseif("${CUDA_VERSION}" LESS 120) # Support for sm_35, sm_37 was removed in CUDA 12
|
||||
set(cuda_nvcc_executable ${CUDA_NVCC_EXECUTABLE})
|
||||
set(cuda_toolkit_root_dir ${CUDA_TOOLKIT_ROOT_DIR})
|
||||
else()
|
||||
message(STATUS "CUDA binaries for ${arch} require CUDA 11 or earlier, skipped.")
|
||||
endif()
|
||||
elseif(${arch} MATCHES ".*_7." AND "${CUDA_VERSION}" LESS 100)
|
||||
message(STATUS "CUDA binaries for ${arch} require CUDA 10.0+, skipped.")
|
||||
elseif(${arch} MATCHES ".*_8.")
|
||||
|
|
|
@ -686,7 +686,7 @@ ccl_device_inline Spectrum bsdf_albedo(ccl_private const ShaderData *sd,
|
|||
albedo *= ((ccl_private const PrincipledSheenBsdf *)sc)->avg_value;
|
||||
break;
|
||||
case CLOSURE_BSDF_HAIR_PRINCIPLED_ID:
|
||||
albedo *= bsdf_principled_hair_albedo(sc);
|
||||
albedo *= bsdf_principled_hair_albedo(sd, sc);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -478,10 +478,18 @@ ccl_device_inline float bsdf_principled_hair_albedo_roughness_scale(
|
|||
return (((((0.245f * x) + 5.574f) * x - 10.73f) * x + 2.532f) * x - 0.215f) * x + 5.969f;
|
||||
}
|
||||
|
||||
ccl_device Spectrum bsdf_principled_hair_albedo(ccl_private const ShaderClosure *sc)
|
||||
ccl_device Spectrum bsdf_principled_hair_albedo(ccl_private const ShaderData *sd,
|
||||
ccl_private const ShaderClosure *sc)
|
||||
{
|
||||
ccl_private PrincipledHairBSDF *bsdf = (ccl_private PrincipledHairBSDF *)sc;
|
||||
return exp(-sqrt(bsdf->sigma) * bsdf_principled_hair_albedo_roughness_scale(bsdf->v));
|
||||
|
||||
const float cos_theta_o = cos_from_sin(dot(sd->wi, safe_normalize(sd->dPdu)));
|
||||
const float cos_gamma_o = cos_from_sin(bsdf->extra->geom.w);
|
||||
const float f = fresnel_dielectric_cos(cos_theta_o * cos_gamma_o, bsdf->eta);
|
||||
|
||||
const float roughness_scale = bsdf_principled_hair_albedo_roughness_scale(bsdf->v);
|
||||
/* TODO(lukas): Adding the Fresnel term here as a workaround until the proper refactor. */
|
||||
return exp(-sqrt(bsdf->sigma) * roughness_scale) + make_spectrum(f);
|
||||
}
|
||||
|
||||
ccl_device_inline Spectrum
|
||||
|
|
|
@ -573,7 +573,7 @@ void ShaderManager::device_update_common(Device * /*device*/,
|
|||
kfilm->is_rec709 = is_rec709;
|
||||
}
|
||||
|
||||
void ShaderManager::device_free_common(Device *, DeviceScene *dscene, Scene *scene)
|
||||
void ShaderManager::device_free_common(Device * /*device*/, DeviceScene *dscene, Scene * /*scene*/)
|
||||
{
|
||||
dscene->shaders.free();
|
||||
}
|
||||
|
|
|
@ -281,6 +281,8 @@ inline T *MEM_new(const char *allocation_name, Args &&...args)
|
|||
*/
|
||||
template<typename T> inline void MEM_delete(const T *ptr)
|
||||
{
|
||||
static_assert(!std::is_void_v<T>,
|
||||
"MEM_delete on a void pointer not possible. Cast it to a non-void type?");
|
||||
if (ptr == nullptr) {
|
||||
/* Support #ptr being null, because C++ `delete` supports that as well. */
|
||||
return;
|
||||
|
|
|
@ -370,6 +370,7 @@ const bTheme U_theme_default = {
|
|||
.clipping_border_3d = RGBA(0x3f3f3fff),
|
||||
.bundle_solid = RGBA(0xc8c8c8ff),
|
||||
.camera_path = RGBA(0x000000ff),
|
||||
.camera_passepartout = RGBA(0x000000),
|
||||
.gp_vertex_size = 3,
|
||||
.gp_vertex = RGBA(0x000000ff),
|
||||
.gp_vertex_select = RGBA(0xff8500ff),
|
||||
|
|
|
@ -30,7 +30,7 @@ def url_prefill_from_blender(*, addon_info=None):
|
|||
"**Blender Version**\n"
|
||||
)
|
||||
fh.write(
|
||||
"Broken: version: %s, branch: %s, commit date: %s %s, hash: `rB%s`\n" % (
|
||||
"Broken: version: %s, branch: %s, commit date: %s %s, hash: `%s`\n" % (
|
||||
bpy.app.version_string,
|
||||
bpy.app.build_branch.decode('utf-8', 'replace'),
|
||||
bpy.app.build_commit_date.decode('utf-8', 'replace'),
|
||||
|
|
|
@ -991,6 +991,7 @@ url_manual_mapping = (
|
|||
("bpy.types.geometrynodeinputmeshfacearea*", "modeling/geometry_nodes/mesh/read/face_area.html#bpy-types-geometrynodeinputmeshfacearea"),
|
||||
("bpy.types.geometrynodeinputsplinecyclic*", "modeling/geometry_nodes/curve/read/is_spline_cyclic.html#bpy-types-geometrynodeinputsplinecyclic"),
|
||||
("bpy.types.geometrynodeinstancestopoints*", "modeling/geometry_nodes/instances/instances_to_points.html#bpy-types-geometrynodeinstancestopoints"),
|
||||
("bpy.types.geometrynodematerialselection*", "modeling/geometry_nodes/material/material_selection.html#bpy-types-geometrynodematerialselection"),
|
||||
("bpy.types.gpencillayer.viewlayer_render*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-viewlayer-render"),
|
||||
("bpy.types.imagepaint.use_normal_falloff*", "sculpt_paint/brush/falloff.html#bpy-types-imagepaint-use-normal-falloff"),
|
||||
("bpy.types.layercollection.hide_viewport*", "editors/outliner/interface.html#bpy-types-layercollection-hide-viewport"),
|
||||
|
@ -2027,6 +2028,7 @@ url_manual_mapping = (
|
|||
("bpy.ops.graph.equalize_handles*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-equalize-handles"),
|
||||
("bpy.ops.mball.delete_metaelems*", "modeling/metas/editing.html#bpy-ops-mball-delete-metaelems"),
|
||||
("bpy.ops.mball.reveal_metaelems*", "modeling/metas/properties.html#bpy-ops-mball-reveal-metaelems"),
|
||||
("bpy.ops.mesh.bridge_edge_loops*", "modeling/meshes/editing/edge/bridge_edge_loops.html#bpy-ops-mesh-bridge-edge-loops"),
|
||||
("bpy.ops.mesh.intersect_boolean*", "modeling/meshes/editing/face/intersect_boolean.html#bpy-ops-mesh-intersect-boolean"),
|
||||
("bpy.ops.mesh.loop_multi_select*", "modeling/meshes/selecting/loops.html#bpy-ops-mesh-loop-multi-select"),
|
||||
("bpy.ops.mesh.vert_connect_path*", "modeling/meshes/editing/vertex/connect_vertex_path.html#bpy-ops-mesh-vert-connect-path"),
|
||||
|
@ -3021,6 +3023,7 @@ url_manual_mapping = (
|
|||
("bpy.types.bakesettings*", "render/cycles/baking.html#bpy-types-bakesettings"),
|
||||
("bpy.types.blendtexture*", "render/materials/legacy_textures/types/blend.html#bpy-types-blendtexture"),
|
||||
("bpy.types.brush.height*", "sculpt_paint/sculpting/tools/layer.html#bpy-types-brush-height"),
|
||||
("bpy.types.brush.jitter*", "sculpt_paint/brush/stroke.html#bpy-types-brush-jitter"),
|
||||
("bpy.types.castmodifier*", "modeling/modifiers/deform/cast.html#bpy-types-castmodifier"),
|
||||
("bpy.types.curve.offset*", "modeling/curves/properties/geometry.html#bpy-types-curve-offset"),
|
||||
("bpy.types.geometrynode*", "modeling/geometry_nodes/index.html#bpy-types-geometrynode"),
|
||||
|
|
|
@ -5629,6 +5629,8 @@ def km_curves(params):
|
|||
("curves.disable_selection", {"type": 'TWO', "value": 'PRESS', "alt": True}, None),
|
||||
*_template_items_select_actions(params, "curves.select_all"),
|
||||
("curves.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
|
||||
("curves.delete", {"type": 'X', "value": 'PRESS'}, None),
|
||||
("curves.delete", {"type": 'DEL', "value": 'PRESS'}, None),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
@ -6345,9 +6347,8 @@ def km_node_link_modal_map(_params):
|
|||
|
||||
return keymap
|
||||
|
||||
|
||||
# Fallback for gizmos that don't have custom a custom key-map.
|
||||
|
||||
|
||||
def km_generic_gizmo(_params):
|
||||
keymap = (
|
||||
"Generic Gizmo",
|
||||
|
|
|
@ -6,8 +6,8 @@ from bpy.types import Operator
|
|||
from bpy.app.translations import pgettext_data as data_
|
||||
|
||||
|
||||
def geometry_node_group_empty_new():
|
||||
group = bpy.data.node_groups.new(data_("Geometry Nodes"), 'GeometryNodeTree')
|
||||
def build_default_empty_geometry_node_group(name):
|
||||
group = bpy.data.node_groups.new(name, 'GeometryNodeTree')
|
||||
group.inputs.new('NodeSocketGeometry', data_("Geometry"))
|
||||
group.outputs.new('NodeSocketGeometry', data_("Geometry"))
|
||||
input_node = group.nodes.new('NodeGroupInput')
|
||||
|
@ -20,8 +20,12 @@ def geometry_node_group_empty_new():
|
|||
input_node.location.x = -200 - input_node.width
|
||||
output_node.location.x = 200
|
||||
|
||||
group.links.new(output_node.inputs[0], input_node.outputs[0])
|
||||
return group
|
||||
|
||||
|
||||
def geometry_node_group_empty_new():
|
||||
group = build_default_empty_geometry_node_group(data_("Geometry Nodes"))
|
||||
group.links.new(group.nodes["Group Input"].outputs[0], group.nodes["Group Output"].inputs[0])
|
||||
return group
|
||||
|
||||
|
||||
|
@ -35,6 +39,158 @@ def geometry_modifier_poll(context):
|
|||
return True
|
||||
|
||||
|
||||
def get_context_modifier(context):
|
||||
if context.area.type == 'PROPERTIES':
|
||||
modifier = context.modifier
|
||||
else:
|
||||
modifier = context.object.modifiers.active
|
||||
if modifier is None or modifier.type != 'NODES':
|
||||
return None
|
||||
return modifier
|
||||
|
||||
|
||||
def edit_geometry_nodes_modifier_poll(context):
|
||||
return get_context_modifier(context) is not None
|
||||
|
||||
|
||||
def socket_idname_to_attribute_type(idname):
|
||||
if idname.startswith("NodeSocketInt"):
|
||||
return "INT"
|
||||
elif idname.startswith("NodeSocketColor"):
|
||||
return "FLOAT_COLOR"
|
||||
elif idname.startswith("NodeSocketVector"):
|
||||
return "FLOAT_VECTOR"
|
||||
elif idname.startswith("NodeSocketBool"):
|
||||
return "BOOLEAN"
|
||||
elif idname.startswith("NodeSocketFloat"):
|
||||
return "FLOAT"
|
||||
raise ValueError("Unsupported socket type")
|
||||
return ""
|
||||
|
||||
|
||||
def modifier_attribute_name_get(modifier, identifier):
|
||||
try:
|
||||
return modifier[identifier + "_attribute_name"]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
|
||||
def modifier_input_use_attribute(modifier, identifier):
|
||||
try:
|
||||
return modifier[identifier + "_use_attribute"] != 0
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
|
||||
def get_socket_with_identifier(sockets, identifier):
|
||||
for socket in sockets:
|
||||
if socket.identifier == identifier:
|
||||
return socket
|
||||
return None
|
||||
|
||||
|
||||
def get_enabled_socket_with_name(sockets, name):
|
||||
for socket in sockets:
|
||||
if socket.name == name and socket.enabled:
|
||||
return socket
|
||||
return None
|
||||
|
||||
|
||||
class MoveModifierToNodes(Operator):
|
||||
"""Move inputs and outputs from in the modifier to a new node group"""
|
||||
|
||||
bl_idname = "object.geometry_nodes_move_to_nodes"
|
||||
bl_label = "Move to Nodes"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return edit_geometry_nodes_modifier_poll(context)
|
||||
|
||||
def execute(self, context):
|
||||
modifier = get_context_modifier(context)
|
||||
if not modifier:
|
||||
return {'CANCELLED'}
|
||||
old_group = modifier.node_group
|
||||
if not old_group:
|
||||
return {'CANCELLED'}
|
||||
|
||||
wrapper_name = old_group.name + ".wrapper"
|
||||
group = build_default_empty_geometry_node_group(wrapper_name)
|
||||
group_node = group.nodes.new("GeometryNodeGroup")
|
||||
group_node.node_tree = old_group
|
||||
group_node.update()
|
||||
|
||||
group_input_node = group.nodes["Group Input"]
|
||||
group_output_node = group.nodes["Group Output"]
|
||||
|
||||
# Copy default values for inputs and create named attribute input nodes.
|
||||
input_nodes = []
|
||||
first_geometry_input = None
|
||||
for input_socket in old_group.inputs:
|
||||
identifier = input_socket.identifier
|
||||
group_node_input = get_socket_with_identifier(group_node.inputs, identifier)
|
||||
if modifier_input_use_attribute(modifier, identifier):
|
||||
input_node = group.nodes.new("GeometryNodeInputNamedAttribute")
|
||||
input_nodes.append(input_node)
|
||||
input_node.data_type = socket_idname_to_attribute_type(input_socket.bl_socket_idname)
|
||||
attribute_name = modifier_attribute_name_get(modifier, identifier)
|
||||
input_node.inputs["Name"].default_value = attribute_name
|
||||
output_socket = get_enabled_socket_with_name(input_node.outputs, "Attribute")
|
||||
group.links.new(output_socket, group_node_input)
|
||||
elif hasattr(input_socket, "default_value"):
|
||||
group_node_input.default_value = modifier[identifier]
|
||||
elif input_socket.bl_socket_idname == 'NodeSocketGeometry':
|
||||
if not first_geometry_input:
|
||||
first_geometry_input = group_node_input
|
||||
|
||||
group.links.new(group_input_node.outputs[0], first_geometry_input)
|
||||
|
||||
# Adjust locations of named attribute input nodes and group input node to make some space.
|
||||
if input_nodes:
|
||||
for i, node in enumerate(input_nodes):
|
||||
node.location.x = -175
|
||||
node.location.y = i * -50
|
||||
group_input_node.location.x = -350
|
||||
|
||||
# Connect outputs to store named attribute nodes to replace modifier attribute outputs.
|
||||
store_nodes = []
|
||||
first_geometry_output = None
|
||||
for output_socket in old_group.outputs:
|
||||
identifier = output_socket.identifier
|
||||
group_node_output = get_socket_with_identifier(group_node.outputs, identifier)
|
||||
attribute_name = modifier_attribute_name_get(modifier, identifier)
|
||||
if attribute_name:
|
||||
store_node = group.nodes.new("GeometryNodeStoreNamedAttribute")
|
||||
store_nodes.append(store_node)
|
||||
store_node.data_type = socket_idname_to_attribute_type(output_socket.bl_socket_idname)
|
||||
store_node.domain = output_socket.attribute_domain
|
||||
store_node.inputs["Name"].default_value = attribute_name
|
||||
input_socket = get_enabled_socket_with_name(store_node.inputs, "Value")
|
||||
group.links.new(group_node_output, input_socket)
|
||||
elif output_socket.bl_socket_idname == 'NodeSocketGeometry':
|
||||
if not first_geometry_output:
|
||||
first_geometry_output = group_node_output
|
||||
|
||||
# Adjust locations of store named attribute nodes and move group output.
|
||||
if store_nodes:
|
||||
for i, node in enumerate(store_nodes):
|
||||
node.location.x = (i + 1) * 175
|
||||
node.location.y = 0
|
||||
group_output_node.location.x = (len(store_nodes) + 1) * 175
|
||||
|
||||
group.links.new(first_geometry_output, store_nodes[0].inputs["Geometry"])
|
||||
for i in range(len(store_nodes) - 1):
|
||||
group.links.new(store_nodes[i].outputs["Geometry"], store_nodes[i + 1].inputs["Geometry"])
|
||||
group.links.new(store_nodes[-1].outputs["Geometry"], group_output_node.inputs["Geometry"])
|
||||
else:
|
||||
group.links.new(first_geometry_output, group_output_node.inputs["Geometry"])
|
||||
|
||||
modifier.node_group = group
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class NewGeometryNodesModifier(Operator):
|
||||
"""Create a new modifier with a new geometry node group"""
|
||||
|
||||
|
@ -48,7 +204,6 @@ class NewGeometryNodesModifier(Operator):
|
|||
|
||||
def execute(self, context):
|
||||
modifier = context.object.modifiers.new(data_("GeometryNodes"), "NODES")
|
||||
|
||||
if not modifier:
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
@ -70,11 +225,7 @@ class NewGeometryNodeTreeAssign(Operator):
|
|||
return geometry_modifier_poll(context)
|
||||
|
||||
def execute(self, context):
|
||||
if context.area.type == 'PROPERTIES':
|
||||
modifier = context.modifier
|
||||
else:
|
||||
modifier = context.object.modifiers.active
|
||||
|
||||
modifier = get_context_modifier(context)
|
||||
if not modifier:
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
@ -87,4 +238,5 @@ class NewGeometryNodeTreeAssign(Operator):
|
|||
classes = (
|
||||
NewGeometryNodesModifier,
|
||||
NewGeometryNodeTreeAssign,
|
||||
MoveModifierToNodes,
|
||||
)
|
||||
|
|
|
@ -36,67 +36,135 @@ class ObjectModeOperator:
|
|||
|
||||
|
||||
class QuickFur(ObjectModeOperator, Operator):
|
||||
"""Add fur setup to the selected objects"""
|
||||
"""Add a fur setup to the selected objects"""
|
||||
bl_idname = "object.quick_fur"
|
||||
bl_label = "Quick Fur"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
density: EnumProperty(
|
||||
name="Fur Density",
|
||||
name="Density",
|
||||
items=(
|
||||
('LIGHT', "Light", ""),
|
||||
('LOW', "Low", ""),
|
||||
('MEDIUM', "Medium", ""),
|
||||
('HEAVY', "Heavy", ""),
|
||||
('HIGH', "High", ""),
|
||||
),
|
||||
default='MEDIUM',
|
||||
)
|
||||
view_percentage: IntProperty(
|
||||
name="View %",
|
||||
min=1, max=100,
|
||||
soft_min=1, soft_max=100,
|
||||
default=10,
|
||||
)
|
||||
length: FloatProperty(
|
||||
name="Length",
|
||||
min=0.001, max=100,
|
||||
soft_min=0.01, soft_max=10,
|
||||
default=0.1,
|
||||
subtype='DISTANCE'
|
||||
)
|
||||
radius: FloatProperty(
|
||||
name="Hair Radius",
|
||||
min=0.0, max=10,
|
||||
soft_min=0.0001, soft_max=0.1,
|
||||
default=0.001,
|
||||
subtype='DISTANCE'
|
||||
)
|
||||
view_percentage: FloatProperty(
|
||||
name="View Percentage",
|
||||
min=0.0, max=1.0,
|
||||
default=1.0,
|
||||
subtype='FACTOR'
|
||||
)
|
||||
apply_hair_guides: BoolProperty(
|
||||
name="Apply Hair Guides",
|
||||
default=True,
|
||||
)
|
||||
use_noise: BoolProperty(
|
||||
name="Noise",
|
||||
default=True,
|
||||
)
|
||||
use_frizz: BoolProperty(
|
||||
name="Frizz",
|
||||
default=True,
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
fake_context = context.copy()
|
||||
mesh_objects = [obj for obj in context.selected_objects
|
||||
if obj.type == 'MESH']
|
||||
|
||||
import os
|
||||
mesh_objects = [obj for obj in context.selected_objects if obj.type == 'MESH']
|
||||
if not mesh_objects:
|
||||
self.report({'ERROR'}, "Select at least one mesh object")
|
||||
return {'CANCELLED'}
|
||||
|
||||
mat = bpy.data.materials.new("Fur Material")
|
||||
if self.density == 'LOW':
|
||||
count = 1000
|
||||
elif self.density == 'MEDIUM':
|
||||
count = 10000
|
||||
elif self.density == 'HIGH':
|
||||
count = 100000
|
||||
|
||||
for obj in mesh_objects:
|
||||
fake_context["object"] = obj
|
||||
bpy.ops.object.particle_system_add(fake_context)
|
||||
node_groups_to_append = {"Generate Hair Curves", "Set Hair Curve Profile", "Interpolate Hair Curves"}
|
||||
if self.use_noise:
|
||||
node_groups_to_append.add("Hair Curves Noise")
|
||||
if self.use_frizz:
|
||||
node_groups_to_append.add("Frizz Hair Curves")
|
||||
assets_directory = os.path.join(bpy.utils.system_resource('DATAFILES'),
|
||||
"assets",
|
||||
"geometry_nodes",
|
||||
"procedural_hair_node_assets.blend",
|
||||
"NodeTree")
|
||||
for name in node_groups_to_append:
|
||||
bpy.ops.wm.append(directory=assets_directory,
|
||||
filename=name,
|
||||
use_recursive=True,
|
||||
do_reuse_local_id=True)
|
||||
generate_group = bpy.data.node_groups["Generate Hair Curves"]
|
||||
interpolate_group = bpy.data.node_groups["Interpolate Hair Curves"]
|
||||
radius_group = bpy.data.node_groups["Set Hair Curve Profile"]
|
||||
noise_group = bpy.data.node_groups["Hair Curves Noise"] if self.use_noise else None
|
||||
frizz_group = bpy.data.node_groups["Frizz Hair Curves"] if self.use_frizz else None
|
||||
|
||||
psys = obj.particle_systems[-1]
|
||||
psys.settings.type = 'HAIR'
|
||||
material = bpy.data.materials.new("Fur Material")
|
||||
|
||||
if self.density == 'LIGHT':
|
||||
psys.settings.count = 100
|
||||
elif self.density == 'MEDIUM':
|
||||
psys.settings.count = 1000
|
||||
elif self.density == 'HEAVY':
|
||||
psys.settings.count = 10000
|
||||
for mesh_object in mesh_objects:
|
||||
mesh = mesh_object.data
|
||||
with context.temp_override(active_object=mesh_object):
|
||||
bpy.ops.object.curves_empty_hair_add()
|
||||
curves_object = context.active_object
|
||||
curves = curves_object.data
|
||||
curves.materials.append(material)
|
||||
|
||||
psys.settings.child_nbr = self.view_percentage
|
||||
psys.settings.hair_length = self.length
|
||||
psys.settings.use_strand_primitive = True
|
||||
psys.settings.use_hair_bspline = True
|
||||
psys.settings.child_type = 'INTERPOLATED'
|
||||
psys.settings.tip_radius = 0.25
|
||||
area = 0.0
|
||||
for poly in mesh.polygons:
|
||||
area += poly.area
|
||||
density = count / area
|
||||
|
||||
obj.data.materials.append(mat)
|
||||
psys.settings.material = len(obj.data.materials)
|
||||
generate_modifier = curves_object.modifiers.new(name="Generate", type='NODES')
|
||||
generate_modifier.node_group = generate_group
|
||||
generate_modifier["Input_2"] = mesh_object
|
||||
generate_modifier["Input_18_attribute_name"] = curves.surface_uv_map
|
||||
generate_modifier["Input_20"] = self.length
|
||||
generate_modifier["Input_22"] = material
|
||||
generate_modifier["Input_15"] = density * 0.01
|
||||
curves_object.modifiers.move(1, 0)
|
||||
|
||||
radius_modifier = curves_object.modifiers.new(name="Set Hair Curve Profile", type='NODES')
|
||||
radius_modifier.node_group = radius_group
|
||||
radius_modifier["Input_3"] = self.radius
|
||||
|
||||
interpolate_modifier = curves_object.modifiers.new(name="Interpolate Hair Curves", type='NODES')
|
||||
interpolate_modifier.node_group = interpolate_group
|
||||
interpolate_modifier["Input_2"] = mesh_object
|
||||
interpolate_modifier["Input_18_attribute_name"] = curves.surface_uv_map
|
||||
interpolate_modifier["Input_15"] = density
|
||||
interpolate_modifier["Input_17"] = self.view_percentage
|
||||
interpolate_modifier["Input_24"] = True
|
||||
|
||||
if noise_group:
|
||||
noise_modifier = curves_object.modifiers.new(name="Hair Curves Noise", type='NODES')
|
||||
noise_modifier.node_group = noise_group
|
||||
|
||||
if frizz_group:
|
||||
frizz_modifier = curves_object.modifiers.new(name="Frizz Hair Curves", type='NODES')
|
||||
frizz_modifier.node_group = frizz_group
|
||||
|
||||
if self.apply_hair_guides:
|
||||
with context.temp_override(object=curves_object):
|
||||
bpy.ops.object.modifier_apply(modifier=generate_modifier.name)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
|
|
@ -1249,7 +1249,31 @@ class WM_OT_doc_view_manual(Operator):
|
|||
# XXX, for some reason all RNA ID's are stored lowercase
|
||||
# Adding case into all ID's isn't worth the hassle so force lowercase.
|
||||
rna_id = rna_id.lower()
|
||||
|
||||
# NOTE: `fnmatch` in Python is slow as it translate the string to a regular-expression
|
||||
# which needs to be compiled (as of Python 3.11), this is slow enough to cause a noticeable
|
||||
# delay when opening manual links (approaching half a second).
|
||||
#
|
||||
# Resolve by matching characters that have a special meaning to `fnmatch`.
|
||||
# The characters that can occur as the first special character are `*?[`.
|
||||
# If any of these are used we must let `fnmatch` run its own matching logic.
|
||||
# However, in most cases a literal prefix is used making it considerably faster
|
||||
# to do a simple `startswith` check before performing a full match.
|
||||
# An alternative solution could be to use `fnmatch` from C which is significantly
|
||||
# faster than Python's, see !104581 for details.
|
||||
import re
|
||||
re_match_non_special = re.compile(r"^[^?\*\[]+").match
|
||||
|
||||
for pattern, url_suffix in url_mapping:
|
||||
|
||||
# Simple optimization, makes a big difference (over 50x speedup).
|
||||
# Even when `non_special.end()` is zero (resulting in an empty-string),
|
||||
# the `startswith` check succeeds so there is no need to check for an empty match.
|
||||
non_special = re_match_non_special(pattern)
|
||||
if non_special is None or not rna_id.startswith(pattern[:non_special.end()]):
|
||||
continue
|
||||
# End simple optimization.
|
||||
|
||||
if fnmatchcase(rna_id, pattern):
|
||||
if verbose:
|
||||
print(" match found: '%s' --> '%s'" % (pattern, url_suffix))
|
||||
|
|
|
@ -1141,6 +1141,11 @@ def brush_texture_settings(layout, brush, sculpt):
|
|||
# texture_sample_bias
|
||||
layout.prop(brush, "texture_sample_bias", slider=True, text="Sample Bias")
|
||||
|
||||
if brush.sculpt_tool == 'DRAW':
|
||||
col = layout.column()
|
||||
col.active = tex_slot.map_mode == 'AREA_PLANE'
|
||||
col.prop(brush, "use_color_as_displacement", text="Vector Displacement")
|
||||
|
||||
|
||||
def brush_mask_texture_settings(layout, brush):
|
||||
mask_tex_slot = brush.mask_texture_slot
|
||||
|
|
|
@ -931,8 +931,14 @@ class SEQUENCER_MT_strip(Menu):
|
|||
|
||||
if has_sequencer:
|
||||
|
||||
layout.operator("sequencer.split", text="Split").type = 'SOFT'
|
||||
layout.operator("sequencer.split", text="Hold Split").type = 'HARD'
|
||||
props = layout.operator("sequencer.split", text="Split")
|
||||
props.type = 'SOFT'
|
||||
props.side = 'RIGHT'
|
||||
|
||||
props = layout.operator("sequencer.split", text="Hold Split")
|
||||
props.type = 'HARD'
|
||||
props.side = 'RIGHT'
|
||||
|
||||
layout.separator()
|
||||
|
||||
if has_sequencer:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2319,21 +2319,15 @@ class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel):
|
|||
bl_label = "New Features"
|
||||
|
||||
def draw(self, context):
|
||||
self._draw_items(context,
|
||||
(({"property": "use_sculpt_tools_tilt"},
|
||||
("blender/blender/issues/82877",
|
||||
"#82877")),
|
||||
({"property": "use_extended_asset_browser"},
|
||||
("blender/blender/projects/10",
|
||||
"Pipeline, Assets & IO Project Page")),
|
||||
({"property": "use_override_templates"},
|
||||
("blender/blender/issues/73318",
|
||||
"Milestone 4")),
|
||||
({"property": "use_new_volume_nodes"},
|
||||
("blender/blender/issues/103248",
|
||||
"#103248")),
|
||||
),
|
||||
)
|
||||
self._draw_items(
|
||||
context, (
|
||||
({"property": "use_sculpt_tools_tilt"}, ("blender/blender/issues/82877", "#82877")),
|
||||
({"property": "use_extended_asset_browser"},
|
||||
("blender/blender/projects/10", "Pipeline, Assets & IO Project Page")),
|
||||
({"property": "use_override_templates"}, ("blender/blender/issues/73318", "Milestone 4")),
|
||||
({"property": "use_new_volume_nodes"}, ("blender/blender/issues/103248", "#103248")),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class USERPREF_PT_experimental_prototypes(ExperimentalPanel, Panel):
|
||||
|
|
|
@ -522,7 +522,8 @@ class _draw_tool_settings_context_mode:
|
|||
|
||||
if curves_tool == 'COMB':
|
||||
layout.prop(brush, "falloff_shape", expand=True)
|
||||
layout.popover("VIEW3D_PT_tools_brush_falloff")
|
||||
layout.popover("VIEW3D_PT_tools_brush_falloff", text="Brush Falloff")
|
||||
layout.popover("VIEW3D_PT_curves_sculpt_parameter_falloff", text="Curve Falloff")
|
||||
elif curves_tool == 'ADD':
|
||||
layout.prop(brush, "falloff_shape", expand=True)
|
||||
layout.prop(brush.curves_sculpt_settings, "add_amount")
|
||||
|
@ -2116,6 +2117,7 @@ class VIEW3D_MT_curve_add(Menu):
|
|||
layout.separator()
|
||||
|
||||
layout.operator("object.curves_empty_hair_add", text="Empty Hair", icon='CURVES_DATA')
|
||||
layout.operator("object.quick_fur", text="Fur", icon='CURVES_DATA')
|
||||
|
||||
experimental = context.preferences.experimental
|
||||
if experimental.use_new_curves_tools:
|
||||
|
@ -3869,6 +3871,7 @@ class VIEW3D_MT_edit_mesh(Menu):
|
|||
layout.menu("VIEW3D_MT_edit_mesh_normals")
|
||||
layout.menu("VIEW3D_MT_edit_mesh_shading")
|
||||
layout.menu("VIEW3D_MT_edit_mesh_weights")
|
||||
layout.operator("mesh.attribute_set")
|
||||
layout.operator_menu_enum("mesh.sort_elements", "type", text="Sort Elements...")
|
||||
|
||||
layout.separator()
|
||||
|
@ -5310,6 +5313,7 @@ class VIEW3D_MT_edit_curves(Menu):
|
|||
|
||||
layout.menu("VIEW3D_MT_transform")
|
||||
layout.separator()
|
||||
layout.operator("curves.delete")
|
||||
|
||||
|
||||
class VIEW3D_MT_object_mode_pie(Menu):
|
||||
|
@ -6720,15 +6724,15 @@ class VIEW3D_PT_overlay_sculpt(Panel):
|
|||
overlay = view.overlay
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(overlay, "sculpt_show_mask", text="")
|
||||
row.prop(overlay, "show_sculpt_mask", text="")
|
||||
sub = row.row()
|
||||
sub.active = overlay.sculpt_show_mask
|
||||
sub.active = overlay.show_sculpt_mask
|
||||
sub.prop(overlay, "sculpt_mode_mask_opacity", text="Mask")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(overlay, "sculpt_show_face_sets", text="")
|
||||
row.prop(overlay, "show_sculpt_face_sets", text="")
|
||||
sub = row.row()
|
||||
sub.active = overlay.sculpt_show_face_sets
|
||||
sub.active = overlay.show_sculpt_face_sets
|
||||
row.prop(overlay, "sculpt_mode_face_sets_opacity", text="Face Sets")
|
||||
|
||||
|
||||
|
@ -6755,6 +6759,13 @@ class VIEW3D_PT_overlay_sculpt_curves(Panel):
|
|||
row.active = overlay.show_overlays
|
||||
row.prop(overlay, "sculpt_mode_mask_opacity", text="Selection Opacity")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.active = overlay.show_overlays
|
||||
row.prop(overlay, "show_sculpt_curves_cage", text="")
|
||||
subrow = row.row(align=True)
|
||||
subrow.active = overlay.show_sculpt_curves_cage
|
||||
subrow.prop(overlay, "sculpt_curves_cage_opacity", text="Cage Opacity")
|
||||
|
||||
|
||||
class VIEW3D_PT_overlay_bones(Panel):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
|
@ -7936,6 +7947,28 @@ class VIEW3D_PT_curves_sculpt_add_shape(Panel):
|
|||
col.prop(brush.curves_sculpt_settings, "points_per_curve", text="Points")
|
||||
|
||||
|
||||
class VIEW3D_PT_curves_sculpt_parameter_falloff(Panel):
|
||||
# Only for popover, these are dummy values.
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'WINDOW'
|
||||
bl_label = "Curves Sculpt Parameter Falloff"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
settings = UnifiedPaintPanel.paint_settings(context)
|
||||
brush = settings.brush
|
||||
|
||||
layout.template_curve_mapping(brush.curves_sculpt_settings, "curve_parameter_falloff")
|
||||
row = layout.row(align=True)
|
||||
row.operator("brush.sculpt_curves_falloff_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
|
||||
row.operator("brush.sculpt_curves_falloff_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
|
||||
row.operator("brush.sculpt_curves_falloff_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
|
||||
row.operator("brush.sculpt_curves_falloff_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
|
||||
row.operator("brush.sculpt_curves_falloff_preset", icon='LINCURVE', text="").shape = 'LINE'
|
||||
row.operator("brush.sculpt_curves_falloff_preset", icon='NOCURVE', text="").shape = 'MAX'
|
||||
|
||||
|
||||
class VIEW3D_PT_curves_sculpt_grow_shrink_scaling(Panel):
|
||||
# Only for popover, these are dummy values.
|
||||
bl_space_type = 'VIEW_3D'
|
||||
|
@ -8213,6 +8246,7 @@ classes = (
|
|||
TOPBAR_PT_gpencil_vertexcolor,
|
||||
TOPBAR_PT_annotation_layers,
|
||||
VIEW3D_PT_curves_sculpt_add_shape,
|
||||
VIEW3D_PT_curves_sculpt_parameter_falloff,
|
||||
VIEW3D_PT_curves_sculpt_grow_shrink_scaling,
|
||||
VIEW3D_PT_viewport_debug,
|
||||
)
|
||||
|
|
|
@ -67,6 +67,9 @@ class AssetLibrary {
|
|||
|
||||
std::unique_ptr<AssetCatalogService> catalog_service;
|
||||
|
||||
/** Assets owned by this library should never be linked. */
|
||||
bool never_link = false;
|
||||
|
||||
friend class AssetLibraryService;
|
||||
|
||||
public:
|
||||
|
|
|
@ -22,6 +22,8 @@ const char *AS_asset_representation_name_get(const AssetRepresentation *asset)
|
|||
AssetMetaData *AS_asset_representation_metadata_get(const AssetRepresentation *asset)
|
||||
ATTR_WARN_UNUSED_RESULT;
|
||||
bool AS_asset_representation_is_local_id(const AssetRepresentation *asset) ATTR_WARN_UNUSED_RESULT;
|
||||
bool AS_asset_representation_is_never_link(const AssetRepresentation *asset)
|
||||
ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -23,11 +23,15 @@ struct ID;
|
|||
|
||||
namespace blender::asset_system {
|
||||
|
||||
class AssetLibrary;
|
||||
|
||||
class AssetRepresentation {
|
||||
AssetIdentifier identifier_;
|
||||
/** Indicate if this is a local or external asset, and as such, which of the union members below
|
||||
* should be used. */
|
||||
const bool is_local_id_ = false;
|
||||
/** Asset library that owns this asset representation. */
|
||||
const AssetLibrary *owner_asset_library_;
|
||||
|
||||
struct ExternalAsset {
|
||||
std::string name;
|
||||
|
@ -44,10 +48,13 @@ class AssetRepresentation {
|
|||
/** Constructs an asset representation for an external ID. The asset will not be editable. */
|
||||
AssetRepresentation(AssetIdentifier &&identifier,
|
||||
StringRef name,
|
||||
std::unique_ptr<AssetMetaData> metadata);
|
||||
std::unique_ptr<AssetMetaData> metadata,
|
||||
const AssetLibrary &owner_asset_library);
|
||||
/** Constructs an asset representation for an ID stored in the current file. This makes the asset
|
||||
* local and fully editable. */
|
||||
AssetRepresentation(AssetIdentifier &&identifier, ID &id);
|
||||
AssetRepresentation(AssetIdentifier &&identifier,
|
||||
ID &id,
|
||||
const AssetLibrary &owner_asset_library);
|
||||
AssetRepresentation(AssetRepresentation &&other);
|
||||
/* Non-copyable type. */
|
||||
AssetRepresentation(const AssetRepresentation &other) = delete;
|
||||
|
@ -65,6 +72,7 @@ class AssetRepresentation {
|
|||
AssetMetaData &get_metadata() const;
|
||||
/** Returns if this asset is stored inside this current file, and as such fully editable. */
|
||||
bool is_local_id() const;
|
||||
const AssetLibrary &owner_asset_library() const;
|
||||
};
|
||||
|
||||
} // namespace blender::asset_system
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup asset_system
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_string_ref.hh"
|
||||
|
||||
namespace blender::asset_system {
|
||||
|
||||
StringRefNull essentials_directory_path();
|
||||
|
||||
}
|
|
@ -17,6 +17,7 @@ set(SRC
|
|||
intern/asset_catalog.cc
|
||||
intern/asset_catalog_path.cc
|
||||
intern/asset_catalog_tree.cc
|
||||
intern/asset_essentials_library.cc
|
||||
intern/asset_identifier.cc
|
||||
intern/asset_library.cc
|
||||
intern/asset_library_service.cc
|
||||
|
@ -30,6 +31,7 @@ set(SRC
|
|||
AS_asset_identifier.hh
|
||||
AS_asset_library.hh
|
||||
AS_asset_representation.hh
|
||||
AS_essentials_library.hh
|
||||
intern/asset_library_service.hh
|
||||
intern/asset_storage.hh
|
||||
intern/utils.hh
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup asset_system
|
||||
*/
|
||||
|
||||
#include "BLI_path_util.h"
|
||||
|
||||
#include "BKE_appdir.h"
|
||||
|
||||
#include "AS_essentials_library.hh"
|
||||
|
||||
namespace blender::asset_system {
|
||||
|
||||
StringRefNull essentials_directory_path()
|
||||
{
|
||||
static std::string path = []() {
|
||||
const char *datafiles_path = BKE_appdir_folder_id(BLENDER_DATAFILES, "assets");
|
||||
return datafiles_path;
|
||||
}();
|
||||
return path;
|
||||
}
|
||||
|
||||
} // namespace blender::asset_system
|
|
@ -169,13 +169,14 @@ AssetRepresentation &AssetLibrary::add_external_asset(StringRef relative_asset_p
|
|||
std::unique_ptr<AssetMetaData> metadata)
|
||||
{
|
||||
AssetIdentifier identifier = asset_identifier_from_library(relative_asset_path);
|
||||
return asset_storage_->add_external_asset(std::move(identifier), name, std::move(metadata));
|
||||
return asset_storage_->add_external_asset(
|
||||
std::move(identifier), name, std::move(metadata), *this);
|
||||
}
|
||||
|
||||
AssetRepresentation &AssetLibrary::add_local_id_asset(StringRef relative_asset_path, ID &id)
|
||||
{
|
||||
AssetIdentifier identifier = asset_identifier_from_library(relative_asset_path);
|
||||
return asset_storage_->add_local_id_asset(std::move(identifier), id);
|
||||
return asset_storage_->add_local_id_asset(std::move(identifier), id, *this);
|
||||
}
|
||||
|
||||
bool AssetLibrary::remove_asset(AssetRepresentation &asset)
|
||||
|
@ -259,6 +260,12 @@ StringRefNull AssetLibrary::root_path() const
|
|||
Vector<AssetLibraryReference> all_valid_asset_library_refs()
|
||||
{
|
||||
Vector<AssetLibraryReference> result;
|
||||
{
|
||||
AssetLibraryReference library_ref{};
|
||||
library_ref.custom_library_index = -1;
|
||||
library_ref.type = ASSET_LIBRARY_ESSENTIALS;
|
||||
result.append(library_ref);
|
||||
}
|
||||
int i;
|
||||
LISTBASE_FOREACH_INDEX (const bUserAssetLibrary *, asset_library, &U.asset_libraries, i) {
|
||||
if (!BLI_is_dir(asset_library->path)) {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "AS_asset_catalog_tree.hh"
|
||||
#include "AS_asset_library.hh"
|
||||
#include "AS_essentials_library.hh"
|
||||
#include "asset_library_service.hh"
|
||||
#include "utils.hh"
|
||||
|
||||
|
@ -60,6 +61,12 @@ AssetLibrary *AssetLibraryService::get_asset_library(
|
|||
const eAssetLibraryType type = eAssetLibraryType(library_reference.type);
|
||||
|
||||
switch (type) {
|
||||
case ASSET_LIBRARY_ESSENTIALS: {
|
||||
const StringRefNull root_path = essentials_directory_path();
|
||||
AssetLibrary *asset_library = get_asset_library_on_disk(root_path);
|
||||
asset_library->never_link = true;
|
||||
return asset_library;
|
||||
}
|
||||
case ASSET_LIBRARY_LOCAL: {
|
||||
/* For the "Current File" library we get the asset library root path based on main. */
|
||||
std::string root_path = bmain ? AS_asset_library_find_suitable_root_path_from_main(bmain) :
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "DNA_asset_types.h"
|
||||
|
||||
#include "AS_asset_identifier.hh"
|
||||
#include "AS_asset_library.hh"
|
||||
#include "AS_asset_representation.h"
|
||||
#include "AS_asset_representation.hh"
|
||||
|
||||
|
@ -17,15 +18,24 @@ namespace blender::asset_system {
|
|||
|
||||
AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier,
|
||||
StringRef name,
|
||||
std::unique_ptr<AssetMetaData> metadata)
|
||||
: identifier_(identifier), is_local_id_(false), external_asset_()
|
||||
std::unique_ptr<AssetMetaData> metadata,
|
||||
const AssetLibrary &owner_asset_library)
|
||||
: identifier_(identifier),
|
||||
is_local_id_(false),
|
||||
owner_asset_library_(&owner_asset_library),
|
||||
external_asset_()
|
||||
{
|
||||
external_asset_.name = name;
|
||||
external_asset_.metadata_ = std::move(metadata);
|
||||
}
|
||||
|
||||
AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier, ID &id)
|
||||
: identifier_(identifier), is_local_id_(true), local_asset_id_(&id)
|
||||
AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier,
|
||||
ID &id,
|
||||
const AssetLibrary &owner_asset_library)
|
||||
: identifier_(identifier),
|
||||
is_local_id_(true),
|
||||
owner_asset_library_(&owner_asset_library),
|
||||
local_asset_id_(&id)
|
||||
{
|
||||
if (!id.asset_data) {
|
||||
throw std::invalid_argument("Passed ID is not an asset");
|
||||
|
@ -75,6 +85,11 @@ bool AssetRepresentation::is_local_id() const
|
|||
return is_local_id_;
|
||||
}
|
||||
|
||||
const AssetLibrary &AssetRepresentation::owner_asset_library() const
|
||||
{
|
||||
return *owner_asset_library_;
|
||||
}
|
||||
|
||||
} // namespace blender::asset_system
|
||||
|
||||
using namespace blender;
|
||||
|
@ -112,4 +127,11 @@ bool AS_asset_representation_is_local_id(const AssetRepresentation *asset_handle
|
|||
return asset->is_local_id();
|
||||
}
|
||||
|
||||
bool AS_asset_representation_is_never_link(const AssetRepresentation *asset_handle)
|
||||
{
|
||||
const asset_system::AssetRepresentation *asset =
|
||||
reinterpret_cast<const asset_system::AssetRepresentation *>(asset_handle);
|
||||
return asset->owner_asset_library().never_link;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -15,18 +15,21 @@
|
|||
|
||||
namespace blender::asset_system {
|
||||
|
||||
AssetRepresentation &AssetStorage::add_local_id_asset(AssetIdentifier &&identifier, ID &id)
|
||||
AssetRepresentation &AssetStorage::add_local_id_asset(AssetIdentifier &&identifier,
|
||||
ID &id,
|
||||
const AssetLibrary &owner_asset_library)
|
||||
{
|
||||
return *local_id_assets_.lookup_key_or_add(
|
||||
std::make_unique<AssetRepresentation>(std::move(identifier), id));
|
||||
std::make_unique<AssetRepresentation>(std::move(identifier), id, owner_asset_library));
|
||||
}
|
||||
|
||||
AssetRepresentation &AssetStorage::add_external_asset(AssetIdentifier &&identifier,
|
||||
StringRef name,
|
||||
std::unique_ptr<AssetMetaData> metadata)
|
||||
std::unique_ptr<AssetMetaData> metadata,
|
||||
const AssetLibrary &owner_asset_library)
|
||||
{
|
||||
return *external_assets_.lookup_key_or_add(
|
||||
std::make_unique<AssetRepresentation>(std::move(identifier), name, std::move(metadata)));
|
||||
return *external_assets_.lookup_key_or_add(std::make_unique<AssetRepresentation>(
|
||||
std::move(identifier), name, std::move(metadata), owner_asset_library));
|
||||
}
|
||||
|
||||
bool AssetStorage::remove_asset(AssetRepresentation &asset)
|
||||
|
|
|
@ -35,9 +35,12 @@ class AssetStorage {
|
|||
/** See #AssetLibrary::add_external_asset(). */
|
||||
AssetRepresentation &add_external_asset(AssetIdentifier &&identifier,
|
||||
StringRef name,
|
||||
std::unique_ptr<AssetMetaData> metadata);
|
||||
std::unique_ptr<AssetMetaData> metadata,
|
||||
const AssetLibrary &owner_asset_library);
|
||||
/** See #AssetLibrary::add_external_asset(). */
|
||||
AssetRepresentation &add_local_id_asset(AssetIdentifier &&identifier, ID &id);
|
||||
AssetRepresentation &add_local_id_asset(AssetIdentifier &&identifier,
|
||||
ID &id,
|
||||
const AssetLibrary &owner_asset_library);
|
||||
|
||||
/** See #AssetLibrary::remove_asset(). */
|
||||
bool remove_asset(AssetRepresentation &asset);
|
||||
|
|
|
@ -46,6 +46,7 @@ struct GeometryDeformation {
|
|||
* function either retrieves the deformation data from the evaluated object, or falls back to
|
||||
* returning the original data.
|
||||
*/
|
||||
GeometryDeformation get_evaluated_curves_deformation(const Object *ob_eval, const Object &ob_orig);
|
||||
GeometryDeformation get_evaluated_curves_deformation(const Depsgraph &depsgraph,
|
||||
const Object &ob_orig);
|
||||
|
||||
|
|
|
@ -137,6 +137,7 @@ bool CustomData_has_referenced(const struct CustomData *data);
|
|||
* implemented for mloopuv/mloopcol, for now.
|
||||
*/
|
||||
void CustomData_data_copy_value(int type, const void *source, void *dest);
|
||||
void CustomData_data_set_default_value(int type, void *elem);
|
||||
|
||||
/**
|
||||
* Mixes the "value" (e.g. mloopuv uv or mloopcol colors) from one block into
|
||||
|
@ -304,8 +305,8 @@ void CustomData_copy_data(const struct CustomData *source,
|
|||
int source_index,
|
||||
int dest_index,
|
||||
int count);
|
||||
void CustomData_copy_data_layer(const CustomData *source,
|
||||
CustomData *dest,
|
||||
void CustomData_copy_data_layer(const struct CustomData *source,
|
||||
struct CustomData *dest,
|
||||
int src_layer_index,
|
||||
int dst_layer_index,
|
||||
int src_index,
|
||||
|
@ -444,7 +445,7 @@ void *CustomData_get_layer_named_for_write(CustomData *data,
|
|||
int totelem);
|
||||
|
||||
int CustomData_get_offset(const struct CustomData *data, int type);
|
||||
int CustomData_get_offset_named(const CustomData *data, int type, const char *name);
|
||||
int CustomData_get_offset_named(const struct CustomData *data, int type, const char *name);
|
||||
int CustomData_get_n_offset(const struct CustomData *data, int type, int n);
|
||||
|
||||
int CustomData_get_layer_index(const struct CustomData *data, int type);
|
||||
|
@ -506,6 +507,8 @@ void CustomData_clear_layer_flag(struct CustomData *data, int type, int flag);
|
|||
|
||||
void CustomData_bmesh_set_default(struct CustomData *data, void **block);
|
||||
void CustomData_bmesh_free_block(struct CustomData *data, void **block);
|
||||
void CustomData_bmesh_alloc_block(struct CustomData *data, void **block);
|
||||
|
||||
/**
|
||||
* Same as #CustomData_bmesh_free_block but zero the memory rather than freeing.
|
||||
*/
|
||||
|
@ -517,24 +520,6 @@ void CustomData_bmesh_free_block_data_exclude_by_type(struct CustomData *data,
|
|||
void *block,
|
||||
eCustomDataMask mask_exclude);
|
||||
|
||||
/**
|
||||
* Copy custom data to/from layers as in mesh/derived-mesh, to edit-mesh
|
||||
* blocks of data. the CustomData's must not be compatible.
|
||||
*
|
||||
* \param use_default_init: initializes data which can't be copied,
|
||||
* typically you'll want to use this if the BM_xxx create function
|
||||
* is called with BM_CREATE_SKIP_CD flag
|
||||
*/
|
||||
void CustomData_to_bmesh_block(const struct CustomData *source,
|
||||
struct CustomData *dest,
|
||||
int src_index,
|
||||
void **dest_block,
|
||||
bool use_default_init);
|
||||
void CustomData_from_bmesh_block(const struct CustomData *source,
|
||||
struct CustomData *dest,
|
||||
void *src_block,
|
||||
int dest_index);
|
||||
|
||||
/**
|
||||
* Query info over types.
|
||||
*/
|
||||
|
@ -743,7 +728,7 @@ void CustomData_blend_write(BlendWriter *writer,
|
|||
|
||||
void CustomData_blend_read(struct BlendDataReader *reader, struct CustomData *data, int count);
|
||||
|
||||
size_t CustomData_get_elem_size(struct CustomDataLayer *layer);
|
||||
size_t CustomData_get_elem_size(const struct CustomDataLayer *layer);
|
||||
|
||||
#ifndef NDEBUG
|
||||
struct DynStr;
|
||||
|
|
|
@ -36,10 +36,10 @@ struct PropertyRNA;
|
|||
/* Data Management */
|
||||
|
||||
/**
|
||||
* Remove the given NLA strip from the NLA track it occupies, free the strip's data,
|
||||
* and the strip itself.
|
||||
* Frees the given NLA strip, and calls #BKE_nlastrip_remove_and_free to
|
||||
* remove and free all children strips.
|
||||
*/
|
||||
void BKE_nlastrip_free(ListBase *strips, struct NlaStrip *strip, bool do_id_user);
|
||||
void BKE_nlastrip_free(struct NlaStrip *strip, bool do_id_user);
|
||||
/**
|
||||
* Remove the given NLA track from the set of NLA tracks, free the track's data,
|
||||
* and the track itself.
|
||||
|
@ -94,10 +94,22 @@ void BKE_nla_tracks_copy_from_adt(struct Main *bmain,
|
|||
struct NlaTrack *BKE_nlatrack_add(struct AnimData *adt,
|
||||
struct NlaTrack *prev,
|
||||
bool is_liboverride);
|
||||
|
||||
/**
|
||||
* Create a NLA Strip referencing the given Action.
|
||||
*/
|
||||
struct NlaStrip *BKE_nlastrip_new(struct bAction *act);
|
||||
|
||||
/*
|
||||
* Removes the given NLA strip from the list of strips provided.
|
||||
*/
|
||||
void BKE_nlastrip_remove(ListBase *strips, struct NlaStrip *strip);
|
||||
|
||||
/*
|
||||
* Removes the given NLA strip from the list of strips provided, and frees it's memory.
|
||||
*/
|
||||
void BKE_nlastrip_remove_and_free(ListBase *strips, struct NlaStrip *strip, const bool do_id_user);
|
||||
|
||||
/**
|
||||
* Add new NLA-strip to the top of the NLA stack - i.e.
|
||||
* into the last track if space, or a new one otherwise.
|
||||
|
@ -139,13 +151,9 @@ void BKE_nlastrips_sort_strips(ListBase *strips);
|
|||
void BKE_nlastrips_add_strip_unsafe(ListBase *strips, struct NlaStrip *strip);
|
||||
|
||||
/**
|
||||
* \brief NULL checks incoming strip and verifies no overlap / invalid
|
||||
* configuration against other strips in NLA Track.
|
||||
*
|
||||
* \param strips:
|
||||
* \param strip:
|
||||
* \return true
|
||||
* \return false
|
||||
* NULL checks incoming strip and verifies no overlap / invalid
|
||||
* configuration against other strips in NLA Track before calling
|
||||
* #BKE_nlastrips_add_strip_unsafe.
|
||||
*/
|
||||
bool BKE_nlastrips_add_strip(ListBase *strips, struct NlaStrip *strip);
|
||||
|
||||
|
@ -215,11 +223,16 @@ bool BKE_nlatrack_has_space(struct NlaTrack *nlt, float start, float end);
|
|||
void BKE_nlatrack_sort_strips(struct NlaTrack *nlt);
|
||||
|
||||
/**
|
||||
* Add the given NLA-Strip to the given NLA-Track, assuming that it
|
||||
* isn't currently attached to another one.
|
||||
* Add the given NLA-Strip to the given NLA-Track.
|
||||
* Calls #BKE_nlastrips_add_strip to check if strip can be added.
|
||||
*/
|
||||
bool BKE_nlatrack_add_strip(struct NlaTrack *nlt, struct NlaStrip *strip, bool is_liboverride);
|
||||
|
||||
/**
|
||||
* Remove the NLA-Strip from the given NLA-Track.
|
||||
*/
|
||||
void BKE_nlatrack_remove_strip(struct NlaTrack *track, struct NlaStrip *strip);
|
||||
|
||||
/**
|
||||
* Get the extents of the given NLA-Track including gaps between strips,
|
||||
* returning whether this succeeded or not
|
||||
|
|
|
@ -249,8 +249,8 @@ set(SRC
|
|||
intern/particle_distribute.c
|
||||
intern/particle_system.c
|
||||
intern/pbvh.cc
|
||||
intern/pbvh_colors.cc
|
||||
intern/pbvh_bmesh.cc
|
||||
intern/pbvh_colors.cc
|
||||
intern/pbvh_pixels.cc
|
||||
intern/pbvh_uv_islands.cc
|
||||
intern/pointcache.c
|
||||
|
|
|
@ -100,6 +100,8 @@ static void brush_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, cons
|
|||
if (brush_src->curves_sculpt_settings != nullptr) {
|
||||
brush_dst->curves_sculpt_settings = MEM_cnew<BrushCurvesSculptSettings>(
|
||||
__func__, *(brush_src->curves_sculpt_settings));
|
||||
brush_dst->curves_sculpt_settings->curve_parameter_falloff = BKE_curvemapping_copy(
|
||||
brush_src->curves_sculpt_settings->curve_parameter_falloff);
|
||||
}
|
||||
|
||||
/* enable fake user by default */
|
||||
|
@ -130,6 +132,7 @@ static void brush_free_data(ID *id)
|
|||
MEM_SAFE_FREE(brush->gpencil_settings);
|
||||
}
|
||||
if (brush->curves_sculpt_settings != nullptr) {
|
||||
BKE_curvemapping_free(brush->curves_sculpt_settings->curve_parameter_falloff);
|
||||
MEM_freeN(brush->curves_sculpt_settings);
|
||||
}
|
||||
|
||||
|
@ -255,6 +258,7 @@ static void brush_blend_write(BlendWriter *writer, ID *id, const void *id_addres
|
|||
}
|
||||
if (brush->curves_sculpt_settings) {
|
||||
BLO_write_struct(writer, BrushCurvesSculptSettings, brush->curves_sculpt_settings);
|
||||
BKE_curvemapping_blend_write(writer, brush->curves_sculpt_settings->curve_parameter_falloff);
|
||||
}
|
||||
if (brush->gradient) {
|
||||
BLO_write_struct(writer, ColorBand, brush->gradient);
|
||||
|
@ -337,6 +341,12 @@ static void brush_blend_read_data(BlendDataReader *reader, ID *id)
|
|||
}
|
||||
|
||||
BLO_read_data_address(reader, &brush->curves_sculpt_settings);
|
||||
if (brush->curves_sculpt_settings) {
|
||||
BLO_read_data_address(reader, &brush->curves_sculpt_settings->curve_parameter_falloff);
|
||||
if (brush->curves_sculpt_settings->curve_parameter_falloff) {
|
||||
BKE_curvemapping_blend_read(reader, brush->curves_sculpt_settings->curve_parameter_falloff);
|
||||
}
|
||||
}
|
||||
|
||||
brush->preview = nullptr;
|
||||
brush->icon_imbuf = nullptr;
|
||||
|
@ -1583,6 +1593,7 @@ void BKE_brush_init_curves_sculpt_settings(Brush *brush)
|
|||
settings->minimum_length = 0.01f;
|
||||
settings->curve_length = 0.3f;
|
||||
settings->density_add_attempts = 100;
|
||||
settings->curve_parameter_falloff = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode)
|
||||
|
|
|
@ -596,7 +596,7 @@ void BKE_crazyspace_api_eval_clear(Object *object)
|
|||
|
||||
namespace blender::bke::crazyspace {
|
||||
|
||||
GeometryDeformation get_evaluated_curves_deformation(const Depsgraph &depsgraph,
|
||||
GeometryDeformation get_evaluated_curves_deformation(const Object *ob_eval,
|
||||
const Object &ob_orig)
|
||||
{
|
||||
BLI_assert(ob_orig.type == OB_CURVES);
|
||||
|
@ -608,7 +608,6 @@ GeometryDeformation get_evaluated_curves_deformation(const Depsgraph &depsgraph,
|
|||
/* Use the undeformed positions by default. */
|
||||
deformation.positions = curves_orig.positions();
|
||||
|
||||
const Object *ob_eval = DEG_get_evaluated_object(&depsgraph, const_cast<Object *>(&ob_orig));
|
||||
if (ob_eval == nullptr) {
|
||||
return deformation;
|
||||
}
|
||||
|
@ -653,4 +652,11 @@ GeometryDeformation get_evaluated_curves_deformation(const Depsgraph &depsgraph,
|
|||
return deformation;
|
||||
}
|
||||
|
||||
GeometryDeformation get_evaluated_curves_deformation(const Depsgraph &depsgraph,
|
||||
const Object &ob_orig)
|
||||
{
|
||||
const Object *ob_eval = DEG_get_evaluated_object(&depsgraph, const_cast<Object *>(&ob_orig));
|
||||
return get_evaluated_curves_deformation(ob_eval, ob_orig);
|
||||
}
|
||||
|
||||
} // namespace blender::bke::crazyspace
|
||||
|
|
|
@ -120,7 +120,7 @@ static void fill_mesh_topology(const int vert_offset,
|
|||
}
|
||||
}
|
||||
|
||||
const bool has_caps = fill_caps && !main_cyclic && profile_cyclic;
|
||||
const bool has_caps = fill_caps && !main_cyclic && profile_cyclic && profile_point_num > 2;
|
||||
if (has_caps) {
|
||||
const int poly_num = main_segment_num * profile_segment_num;
|
||||
const int cap_loop_offset = loop_offset + poly_num * 4;
|
||||
|
@ -271,7 +271,7 @@ static ResultOffsets calculate_result_offsets(const CurvesInfo &info, const bool
|
|||
const int profile_point_num = profile_offsets.size(i_profile);
|
||||
const int profile_segment_num = curves::segments_num(profile_point_num, profile_cyclic);
|
||||
|
||||
const bool has_caps = fill_caps && !main_cyclic && profile_cyclic;
|
||||
const bool has_caps = fill_caps && !main_cyclic && profile_cyclic && profile_point_num > 2;
|
||||
const int tube_face_num = main_segment_num * profile_segment_num;
|
||||
|
||||
vert_offset += main_point_num * profile_point_num;
|
||||
|
|
|
@ -3654,7 +3654,7 @@ void CustomData_bmesh_free_block_data(CustomData *data, void *block)
|
|||
}
|
||||
}
|
||||
|
||||
static void CustomData_bmesh_alloc_block(CustomData *data, void **block)
|
||||
void CustomData_bmesh_alloc_block(CustomData *data, void **block)
|
||||
{
|
||||
if (*block) {
|
||||
CustomData_bmesh_free_block(data, block);
|
||||
|
@ -3689,19 +3689,23 @@ void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data,
|
|||
}
|
||||
}
|
||||
|
||||
static void CustomData_bmesh_set_default_n(CustomData *data, void **block, const int n)
|
||||
void CustomData_data_set_default_value(const int type, void *elem)
|
||||
{
|
||||
int offset = data->layers[n].offset;
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[n].type);
|
||||
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
|
||||
if (typeInfo->set_default_value) {
|
||||
typeInfo->set_default_value(POINTER_OFFSET(*block, offset), 1);
|
||||
typeInfo->set_default_value(elem, 1);
|
||||
}
|
||||
else {
|
||||
memset(POINTER_OFFSET(*block, offset), 0, typeInfo->size);
|
||||
memset(elem, 0, typeInfo->size);
|
||||
}
|
||||
}
|
||||
|
||||
static void CustomData_bmesh_set_default_n(CustomData *data, void **block, const int n)
|
||||
{
|
||||
const int offset = data->layers[n].offset;
|
||||
CustomData_data_set_default_value(data->layers[n].type, POINTER_OFFSET(*block, offset));
|
||||
}
|
||||
|
||||
void CustomData_bmesh_set_default(CustomData *data, void **block)
|
||||
{
|
||||
if (*block == nullptr) {
|
||||
|
@ -3891,8 +3895,8 @@ void CustomData_data_copy_value(int type, const void *source, void *dest)
|
|||
return;
|
||||
}
|
||||
|
||||
if (typeInfo->copyvalue) {
|
||||
typeInfo->copyvalue(source, dest, CDT_MIX_NOMIX, 0.0f);
|
||||
if (typeInfo->copy) {
|
||||
typeInfo->copy(source, dest, 1);
|
||||
}
|
||||
else {
|
||||
memcpy(dest, source, typeInfo->size);
|
||||
|
@ -4067,115 +4071,6 @@ void CustomData_bmesh_interp(CustomData *data,
|
|||
}
|
||||
}
|
||||
|
||||
void CustomData_to_bmesh_block(const CustomData *source,
|
||||
CustomData *dest,
|
||||
int src_index,
|
||||
void **dest_block,
|
||||
bool use_default_init)
|
||||
{
|
||||
if (*dest_block == nullptr) {
|
||||
CustomData_bmesh_alloc_block(dest, dest_block);
|
||||
}
|
||||
|
||||
/* copies a layer at a time */
|
||||
int dest_i = 0;
|
||||
for (int src_i = 0; src_i < source->totlayer; src_i++) {
|
||||
|
||||
/* find the first dest layer with type >= the source type
|
||||
* (this should work because layers are ordered by type)
|
||||
*/
|
||||
while (dest_i < dest->totlayer && dest->layers[dest_i].type < source->layers[src_i].type) {
|
||||
if (use_default_init) {
|
||||
CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
|
||||
}
|
||||
dest_i++;
|
||||
}
|
||||
|
||||
/* if there are no more dest layers, we're done */
|
||||
if (dest_i >= dest->totlayer) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* if we found a matching layer, copy the data */
|
||||
if (dest->layers[dest_i].type == source->layers[src_i].type) {
|
||||
int offset = dest->layers[dest_i].offset;
|
||||
const void *src_data = source->layers[src_i].data;
|
||||
void *dest_data = POINTER_OFFSET(*dest_block, offset);
|
||||
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(dest->layers[dest_i].type);
|
||||
const size_t src_offset = size_t(src_index) * typeInfo->size;
|
||||
|
||||
if (typeInfo->copy) {
|
||||
typeInfo->copy(POINTER_OFFSET(src_data, src_offset), dest_data, 1);
|
||||
}
|
||||
else {
|
||||
memcpy(dest_data, POINTER_OFFSET(src_data, src_offset), typeInfo->size);
|
||||
}
|
||||
|
||||
/* if there are multiple source & dest layers of the same type,
|
||||
* we don't want to copy all source layers to the same dest, so
|
||||
* increment dest_i
|
||||
*/
|
||||
dest_i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_default_init) {
|
||||
while (dest_i < dest->totlayer) {
|
||||
CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
|
||||
dest_i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CustomData_from_bmesh_block(const CustomData *source,
|
||||
CustomData *dest,
|
||||
void *src_block,
|
||||
int dest_index)
|
||||
{
|
||||
/* copies a layer at a time */
|
||||
int dest_i = 0;
|
||||
for (int src_i = 0; src_i < source->totlayer; src_i++) {
|
||||
if (source->layers[src_i].flag & CD_FLAG_NOCOPY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* find the first dest layer with type >= the source type
|
||||
* (this should work because layers are ordered by type)
|
||||
*/
|
||||
while (dest_i < dest->totlayer && dest->layers[dest_i].type < source->layers[src_i].type) {
|
||||
dest_i++;
|
||||
}
|
||||
|
||||
/* if there are no more dest layers, we're done */
|
||||
if (dest_i >= dest->totlayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* if we found a matching layer, copy the data */
|
||||
if (dest->layers[dest_i].type == source->layers[src_i].type) {
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(dest->layers[dest_i].type);
|
||||
int offset = source->layers[src_i].offset;
|
||||
const void *src_data = POINTER_OFFSET(src_block, offset);
|
||||
void *dst_data = POINTER_OFFSET(dest->layers[dest_i].data,
|
||||
size_t(dest_index) * typeInfo->size);
|
||||
|
||||
if (typeInfo->copy) {
|
||||
typeInfo->copy(src_data, dst_data, 1);
|
||||
}
|
||||
else {
|
||||
memcpy(dst_data, src_data, typeInfo->size);
|
||||
}
|
||||
|
||||
/* if there are multiple source & dest layers of the same type,
|
||||
* we don't want to copy all source layers to the same dest, so
|
||||
* increment dest_i
|
||||
*/
|
||||
dest_i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CustomData_file_write_info(int type, const char **r_struct_name, int *r_struct_num)
|
||||
{
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
|
||||
|
@ -5308,7 +5203,7 @@ eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
|
|||
|
||||
} // namespace blender::bke
|
||||
|
||||
size_t CustomData_get_elem_size(CustomDataLayer *layer)
|
||||
size_t CustomData_get_elem_size(const CustomDataLayer *layer)
|
||||
{
|
||||
return LAYERTYPEINFO[layer->type].size;
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ static void nla_tweakmode_find_active(const ListBase /* NlaTrack */ *nla_tracks,
|
|||
|
||||
/* Freeing ------------------------------------------- */
|
||||
|
||||
void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip, bool do_id_user)
|
||||
void BKE_nlastrip_free(NlaStrip *strip, const bool do_id_user)
|
||||
{
|
||||
NlaStrip *cs, *csn;
|
||||
|
||||
|
@ -73,7 +73,7 @@ void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip, bool do_id_user)
|
|||
/* free child-strips */
|
||||
for (cs = strip->strips.first; cs; cs = csn) {
|
||||
csn = cs->next;
|
||||
BKE_nlastrip_free(&strip->strips, cs, do_id_user);
|
||||
BKE_nlastrip_remove_and_free(&strip->strips, cs, do_id_user);
|
||||
}
|
||||
|
||||
/* remove reference to action */
|
||||
|
@ -81,10 +81,6 @@ void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip, bool do_id_user)
|
|||
id_us_min(&strip->act->id);
|
||||
}
|
||||
|
||||
/* free remapping info */
|
||||
// if (strip->remap)
|
||||
// BKE_animremap_free();
|
||||
|
||||
/* free own F-Curves */
|
||||
BKE_fcurves_free(&strip->fcurves);
|
||||
|
||||
|
@ -92,12 +88,7 @@ void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip, bool do_id_user)
|
|||
free_fmodifiers(&strip->modifiers);
|
||||
|
||||
/* free the strip itself */
|
||||
if (strips) {
|
||||
BLI_freelinkN(strips, strip);
|
||||
}
|
||||
else {
|
||||
MEM_freeN(strip);
|
||||
}
|
||||
MEM_freeN(strip);
|
||||
}
|
||||
|
||||
void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt, bool do_id_user)
|
||||
|
@ -112,7 +103,7 @@ void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt, bool do_id_user)
|
|||
/* free strips */
|
||||
for (strip = nlt->strips.first; strip; strip = stripn) {
|
||||
stripn = strip->next;
|
||||
BKE_nlastrip_free(&nlt->strips, strip, do_id_user);
|
||||
BKE_nlastrip_remove_and_free(&nlt->strips, strip, do_id_user);
|
||||
}
|
||||
|
||||
/* free NLA track itself now */
|
||||
|
@ -875,7 +866,7 @@ void BKE_nlastrips_clear_metastrip(ListBase *strips, NlaStrip *strip)
|
|||
}
|
||||
|
||||
/* free the meta-strip now */
|
||||
BKE_nlastrip_free(strips, strip, true);
|
||||
BKE_nlastrip_remove_and_free(strips, strip, true);
|
||||
}
|
||||
|
||||
void BKE_nlastrips_clear_metas(ListBase *strips, bool only_sel, bool only_temp)
|
||||
|
@ -1190,6 +1181,12 @@ bool BKE_nlatrack_add_strip(NlaTrack *nlt, NlaStrip *strip, const bool is_libove
|
|||
return BKE_nlastrips_add_strip(&nlt->strips, strip);
|
||||
}
|
||||
|
||||
void BKE_nlatrack_remove_strip(NlaTrack *track, NlaStrip *strip)
|
||||
{
|
||||
BLI_assert(track);
|
||||
BKE_nlastrip_remove(&track->strips, strip);
|
||||
}
|
||||
|
||||
bool BKE_nlatrack_get_bounds(NlaTrack *nlt, float bounds[2])
|
||||
{
|
||||
NlaStrip *strip;
|
||||
|
@ -1318,6 +1315,18 @@ NlaStrip *BKE_nlastrip_find_active(NlaTrack *nlt)
|
|||
return nlastrip_find_active(&nlt->strips);
|
||||
}
|
||||
|
||||
void BKE_nlastrip_remove(ListBase *strips, NlaStrip *strip)
|
||||
{
|
||||
BLI_assert(strips);
|
||||
BLI_remlink(strips, strip);
|
||||
}
|
||||
|
||||
void BKE_nlastrip_remove_and_free(ListBase *strips, NlaStrip *strip, const bool do_id_user)
|
||||
{
|
||||
BKE_nlastrip_remove(strips, strip);
|
||||
BKE_nlastrip_free(strip, do_id_user);
|
||||
}
|
||||
|
||||
void BKE_nlastrip_set_active(AnimData *adt, NlaStrip *strip)
|
||||
{
|
||||
NlaTrack *nlt;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2023 Blender Foundation. All rights reserved. */
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
|
||||
#include "BKE_nla.h"
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
|
@ -20,19 +22,19 @@ TEST(nla_strip, BKE_nlastrip_recalculate_blend)
|
|||
strip.start = 1;
|
||||
strip.end = 10;
|
||||
|
||||
/* Scaling a strip up doesn't affect the blend in/out value */
|
||||
/* Scaling a strip up doesn't affect the blend in/out value. */
|
||||
strip.end = 20;
|
||||
BKE_nlastrip_recalculate_blend(&strip);
|
||||
EXPECT_FLOAT_EQ(strip.blendin, 4.0);
|
||||
EXPECT_FLOAT_EQ(strip.blendout, 5.0);
|
||||
|
||||
/* Scaling a strip down affects the blend-in value before the blend-out value */
|
||||
/* Scaling a strip down affects the blend-in value before the blend-out value. */
|
||||
strip.end = 7;
|
||||
BKE_nlastrip_recalculate_blend(&strip);
|
||||
EXPECT_FLOAT_EQ(strip.blendin, 1.0);
|
||||
EXPECT_FLOAT_EQ(strip.blendout, 5.0);
|
||||
|
||||
/* Scaling a strip down to nothing updates the blend in/out values accordingly */
|
||||
/* Scaling a strip down to nothing updates the blend in/out values accordingly. */
|
||||
strip.end = 1.1;
|
||||
BKE_nlastrip_recalculate_blend(&strip);
|
||||
EXPECT_FLOAT_EQ(strip.blendin, 0.0);
|
||||
|
@ -63,4 +65,30 @@ TEST(nla_strip, BKE_nlastrips_add_strip)
|
|||
EXPECT_TRUE(BKE_nlastrips_add_strip(&strips, &strip2));
|
||||
}
|
||||
|
||||
TEST(nla_track, BKE_nlatrack_remove_strip)
|
||||
{
|
||||
NlaTrack track{};
|
||||
ListBase strips{};
|
||||
NlaStrip strip1{};
|
||||
strip1.start = 0;
|
||||
strip1.end = 10;
|
||||
|
||||
NlaStrip strip2{};
|
||||
strip2.start = 11;
|
||||
strip2.end = 20;
|
||||
|
||||
// Add NLA strips to the NLATrack.
|
||||
BKE_nlastrips_add_strip(&strips, &strip1);
|
||||
BKE_nlastrips_add_strip(&strips, &strip2);
|
||||
track.strips = strips;
|
||||
|
||||
// ensure we have 2 strips in the track.
|
||||
EXPECT_EQ(2, BLI_listbase_count(&track.strips));
|
||||
|
||||
BKE_nlatrack_remove_strip(&track, &strip2);
|
||||
EXPECT_EQ(1, BLI_listbase_count(&track.strips));
|
||||
// ensure the correct strip was removed.
|
||||
EXPECT_EQ(-1, BLI_findindex(&track.strips, &strip2));
|
||||
}
|
||||
|
||||
} // namespace blender::bke::tests
|
||||
|
|
|
@ -265,7 +265,7 @@ static DupliObject *make_dupli(const DupliContext *ctx,
|
|||
|
||||
/* Store geometry set data for attribute lookup in innermost to outermost
|
||||
* order, copying only non-null entries to save space. */
|
||||
const int max_instance = sizeof(dob->instance_data) / sizeof(void *);
|
||||
const int max_instance = ARRAY_SIZE(dob->instance_data);
|
||||
int next_instance = 0;
|
||||
if (geometry != nullptr) {
|
||||
dob->instance_idx[next_instance] = int(instance_index);
|
||||
|
@ -1821,7 +1821,7 @@ static bool find_geonode_attribute_rgba(const DupliObject *dupli,
|
|||
using namespace blender;
|
||||
|
||||
/* Loop over layers from innermost to outermost. */
|
||||
for (const int i : IndexRange(sizeof(dupli->instance_data) / sizeof(void *))) {
|
||||
for (const int i : IndexRange(ARRAY_SIZE(dupli->instance_data))) {
|
||||
/* Skip non-geonode layers. */
|
||||
if (dupli->instance_data[i] == nullptr) {
|
||||
continue;
|
||||
|
|
|
@ -1704,7 +1704,7 @@ static void rigidbody_update_sim_ob(Depsgraph *depsgraph, Object *ob, RigidBodyO
|
|||
}
|
||||
}
|
||||
|
||||
/* Make transformed objects temporarily kinmatic
|
||||
/* Make transformed objects temporarily kinematic
|
||||
* so that they can be moved by the user during simulation. */
|
||||
if (is_selected && (G.moving & G_TRANSFORM_OBJ)) {
|
||||
RB_body_set_kinematic_state(rbo->shared->physics_object, true);
|
||||
|
|
|
@ -352,7 +352,7 @@ struct StaticOrHeapIntStorage {
|
|||
|
||||
static void static_or_heap_storage_init(StaticOrHeapIntStorage *storage)
|
||||
{
|
||||
storage->static_storage_len = sizeof(storage->static_storage) / sizeof(*storage->static_storage);
|
||||
storage->static_storage_len = ARRAY_SIZE(storage->static_storage);
|
||||
storage->heap_storage = nullptr;
|
||||
storage->heap_storage_len = 0;
|
||||
}
|
||||
|
|
|
@ -538,13 +538,14 @@ void tracking_cameraIntrinscisOptionsFromTracking(
|
|||
void tracking_trackingCameraFromIntrinscisOptions(
|
||||
MovieTracking *tracking, const libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
|
||||
{
|
||||
float aspy = 1.0f / tracking->camera.pixel_aspect;
|
||||
MovieTrackingCamera *camera = &tracking->camera;
|
||||
|
||||
camera->focal = camera_intrinsics_options->focal_length;
|
||||
|
||||
/* NOTE: The image size stored in the `camera_intrinsics_options` is aspect-ratio corrected,
|
||||
* so there is no need to "un-apply" it from the principal point. */
|
||||
const float principal_px[2] = {camera_intrinsics_options->principal_point_x,
|
||||
camera_intrinsics_options->principal_point_y / (double)aspy};
|
||||
camera_intrinsics_options->principal_point_y};
|
||||
|
||||
tracking_principal_point_pixel_to_normalized(principal_px,
|
||||
camera_intrinsics_options->image_width,
|
||||
|
|
|
@ -97,8 +97,9 @@ MINLINE float saacos(float fac);
|
|||
MINLINE float saasin(float fac);
|
||||
MINLINE float sasqrt(float fac);
|
||||
|
||||
MINLINE float interpf(float a, float b, float t);
|
||||
MINLINE double interpd(double a, double b, double t);
|
||||
/* Compute linear interpolation (lerp) between origin and target. */
|
||||
MINLINE float interpf(float target, float origin, float t);
|
||||
MINLINE double interpd(double target, double origin, double t);
|
||||
|
||||
MINLINE float ratiof(float min, float max, float pos);
|
||||
MINLINE double ratiod(double min, double max, double pos);
|
||||
|
|
|
@ -806,6 +806,10 @@ extern bool BLI_memory_is_zero(const void *arr, size_t arr_size);
|
|||
{ \
|
||||
return a = (_enum_type)(uint64_t(a) & uint64_t(b)); \
|
||||
} \
|
||||
inline _enum_type &operator^=(_enum_type &a, _enum_type b) \
|
||||
{ \
|
||||
return a = (_enum_type)(uint64_t(a) ^ uint64_t(b)); \
|
||||
} \
|
||||
} /* extern "C++" */
|
||||
|
||||
#else
|
||||
|
|
|
@ -281,10 +281,10 @@ set(SRC
|
|||
BLI_math_solvers.h
|
||||
BLI_math_statistics.h
|
||||
BLI_math_time.h
|
||||
BLI_math_vector_mpq_types.hh
|
||||
BLI_math_vector_types.hh
|
||||
BLI_math_vector.h
|
||||
BLI_math_vector.hh
|
||||
BLI_math_vector_mpq_types.hh
|
||||
BLI_math_vector_types.hh
|
||||
BLI_memarena.h
|
||||
BLI_memblock.h
|
||||
BLI_memiter.h
|
||||
|
@ -492,13 +492,13 @@ if(WITH_GTESTS)
|
|||
tests/BLI_math_bits_test.cc
|
||||
tests/BLI_math_color_test.cc
|
||||
tests/BLI_math_geom_test.cc
|
||||
tests/BLI_math_matrix_types_test.cc
|
||||
tests/BLI_math_matrix_test.cc
|
||||
tests/BLI_math_matrix_types_test.cc
|
||||
tests/BLI_math_rotation_test.cc
|
||||
tests/BLI_math_solvers_test.cc
|
||||
tests/BLI_math_time_test.cc
|
||||
tests/BLI_math_vector_types_test.cc
|
||||
tests/BLI_math_vector_test.cc
|
||||
tests/BLI_math_vector_types_test.cc
|
||||
tests/BLI_memiter_test.cc
|
||||
tests/BLI_memory_utils_test.cc
|
||||
tests/BLI_mesh_boolean_test.cc
|
||||
|
|
|
@ -612,6 +612,25 @@ TEST(string, StrFormatIntegerUnits)
|
|||
EXPECT_STREQ("-2B", size_str);
|
||||
}
|
||||
|
||||
TEST(string, StringNLen)
|
||||
{
|
||||
EXPECT_EQ(0, BLI_strnlen("", 0));
|
||||
EXPECT_EQ(0, BLI_strnlen("", 1));
|
||||
EXPECT_EQ(0, BLI_strnlen("", 100));
|
||||
|
||||
EXPECT_EQ(0, BLI_strnlen("x", 0));
|
||||
EXPECT_EQ(1, BLI_strnlen("x", 1));
|
||||
EXPECT_EQ(1, BLI_strnlen("x", 100));
|
||||
|
||||
// ü is \xc3\xbc
|
||||
EXPECT_EQ(2, BLI_strnlen("ü", 100));
|
||||
|
||||
EXPECT_EQ(0, BLI_strnlen("this is a longer string", 0));
|
||||
EXPECT_EQ(1, BLI_strnlen("this is a longer string", 1));
|
||||
EXPECT_EQ(5, BLI_strnlen("this is a longer string", 5));
|
||||
EXPECT_EQ(47, BLI_strnlen("This string writes about an agent without name.", 100));
|
||||
}
|
||||
|
||||
struct WordInfo {
|
||||
WordInfo() = default;
|
||||
WordInfo(int start, int end) : start(start), end(end)
|
||||
|
|
|
@ -1601,6 +1601,12 @@ static bool version_merge_still_offsets(Sequence *seq, void * /*user_data*/)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool version_fix_delete_flag(Sequence *seq, void * /*user_data*/)
|
||||
{
|
||||
seq->flag &= ~SEQ_FLAG_DELETE;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Those `version_liboverride_rnacollections_*` functions mimic the old, pre-3.0 code to find
|
||||
* anchor and source items in the given list of modifiers, constraints etc., using only the
|
||||
* `subitem_local` data of the override property operation.
|
||||
|
@ -3926,6 +3932,35 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
}
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
|
||||
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
|
||||
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
|
||||
if (sl->spacetype == SPACE_VIEW3D) {
|
||||
View3D *v3d = (View3D *)sl;
|
||||
v3d->overlay.flag |= V3D_OVERLAY_SCULPT_CURVES_CAGE;
|
||||
v3d->overlay.sculpt_curves_cage_opacity = 0.5f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Fix possible uncleared `SEQ_FLAG_DELETE` flag */
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
Editing *ed = SEQ_editing_get(scene);
|
||||
if (ed != nullptr) {
|
||||
SEQ_for_each_callback(&ed->seqbase, version_fix_delete_flag, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
|
||||
if (brush->ob_mode == OB_MODE_SCULPT_CURVES) {
|
||||
if (brush->curves_sculpt_settings->curve_parameter_falloff == nullptr) {
|
||||
brush->curves_sculpt_settings->curve_parameter_falloff = BKE_curvemapping_add(
|
||||
1, 0.0f, 0.0f, 1.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Keep this block, even when empty. */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
#include "BLI_span.hh"
|
||||
#include "BLI_string_ref.hh"
|
||||
#include "BLI_task.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_customdata.h"
|
||||
|
@ -110,6 +111,7 @@ using blender::IndexRange;
|
|||
using blender::MutableSpan;
|
||||
using blender::Span;
|
||||
using blender::StringRef;
|
||||
using blender::Vector;
|
||||
|
||||
static char bm_edge_flag_from_mflag(const short mflag)
|
||||
{
|
||||
|
@ -164,6 +166,63 @@ static BMFace *bm_face_create_from_mpoly(BMesh &bm,
|
|||
return BM_face_create(&bm, verts.data(), edges.data(), loops.size(), nullptr, BM_CREATE_SKIP_CD);
|
||||
}
|
||||
|
||||
struct MeshToBMeshLayerInfo {
|
||||
eCustomDataType type;
|
||||
/** The layer's position in the BMesh element's data block. */
|
||||
int bmesh_offset;
|
||||
/** The mesh's #CustomDataLayer::data. When null, the BMesh block is set to its default value. */
|
||||
const void *mesh_data;
|
||||
/** The size of every custom data element. */
|
||||
size_t elem_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate the necessary information to copy every data layer from the Mesh to the BMesh.
|
||||
*/
|
||||
static Vector<MeshToBMeshLayerInfo> mesh_to_bm_copy_info_calc(const CustomData &mesh_data,
|
||||
CustomData &bm_data)
|
||||
{
|
||||
Vector<MeshToBMeshLayerInfo> infos;
|
||||
std::array<int, CD_NUMTYPES> per_type_index;
|
||||
per_type_index.fill(0);
|
||||
for (const int i : IndexRange(bm_data.totlayer)) {
|
||||
const CustomDataLayer &bm_layer = bm_data.layers[i];
|
||||
const eCustomDataType type = eCustomDataType(bm_layer.type);
|
||||
const int mesh_layer_index =
|
||||
bm_layer.name[0] == '\0' ?
|
||||
CustomData_get_layer_index_n(&mesh_data, type, per_type_index[type]) :
|
||||
CustomData_get_named_layer_index(&mesh_data, type, bm_layer.name);
|
||||
|
||||
MeshToBMeshLayerInfo info{};
|
||||
info.type = type;
|
||||
info.bmesh_offset = bm_layer.offset;
|
||||
info.mesh_data = (mesh_layer_index == -1) ? nullptr : mesh_data.layers[mesh_layer_index].data;
|
||||
info.elem_size = CustomData_get_elem_size(&bm_layer);
|
||||
infos.append(info);
|
||||
|
||||
per_type_index[type]++;
|
||||
}
|
||||
return infos;
|
||||
}
|
||||
|
||||
static void mesh_attributes_copy_to_bmesh_block(CustomData &data,
|
||||
const Span<MeshToBMeshLayerInfo> copy_info,
|
||||
const int mesh_index,
|
||||
BMHeader &header)
|
||||
{
|
||||
CustomData_bmesh_alloc_block(&data, &header.data);
|
||||
for (const MeshToBMeshLayerInfo &info : copy_info) {
|
||||
if (info.mesh_data) {
|
||||
CustomData_data_copy_value(info.type,
|
||||
POINTER_OFFSET(info.mesh_data, info.elem_size * mesh_index),
|
||||
POINTER_OFFSET(header.data, info.bmesh_offset));
|
||||
}
|
||||
else {
|
||||
CustomData_data_set_default_value(info.type, POINTER_OFFSET(header.data, info.bmesh_offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshParams *params)
|
||||
{
|
||||
if (!me) {
|
||||
|
@ -259,6 +318,11 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
|
|||
CustomData_bmesh_merge(&mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, bm, BM_LOOP);
|
||||
}
|
||||
|
||||
const Vector<MeshToBMeshLayerInfo> vert_info = mesh_to_bm_copy_info_calc(mesh_vdata, bm->vdata);
|
||||
const Vector<MeshToBMeshLayerInfo> edge_info = mesh_to_bm_copy_info_calc(mesh_edata, bm->edata);
|
||||
const Vector<MeshToBMeshLayerInfo> poly_info = mesh_to_bm_copy_info_calc(mesh_pdata, bm->pdata);
|
||||
const Vector<MeshToBMeshLayerInfo> loop_info = mesh_to_bm_copy_info_calc(mesh_ldata, bm->ldata);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Shape Key */
|
||||
int tot_shape_keys = 0;
|
||||
|
@ -393,8 +457,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
|
|||
copy_v3_v3(v->no, vert_normals[i]);
|
||||
}
|
||||
|
||||
/* Copy Custom Data */
|
||||
CustomData_to_bmesh_block(&mesh_vdata, &bm->vdata, i, &v->head.data, true);
|
||||
mesh_attributes_copy_to_bmesh_block(bm->vdata, vert_info, i, v->head);
|
||||
|
||||
/* Set shape key original index. */
|
||||
if (cd_shape_keyindex_offset != -1) {
|
||||
|
@ -432,8 +495,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
|
|||
BM_elem_flag_enable(e, BM_ELEM_SMOOTH);
|
||||
}
|
||||
|
||||
/* Copy Custom Data */
|
||||
CustomData_to_bmesh_block(&mesh_edata, &bm->edata, i, &e->head.data, true);
|
||||
mesh_attributes_copy_to_bmesh_block(bm->edata, edge_info, i, e->head);
|
||||
}
|
||||
if (is_new) {
|
||||
bm->elem_index_dirty &= ~BM_EDGE; /* Added in order, clear dirty flag. */
|
||||
|
@ -491,12 +553,11 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
|
|||
/* Don't use 'j' since we may have skipped some faces, hence some loops. */
|
||||
BM_elem_index_set(l_iter, totloops++); /* set_ok */
|
||||
|
||||
/* Save index of corresponding #MLoop. */
|
||||
CustomData_to_bmesh_block(&mesh_ldata, &bm->ldata, j++, &l_iter->head.data, true);
|
||||
mesh_attributes_copy_to_bmesh_block(bm->ldata, loop_info, j, l_iter->head);
|
||||
j++;
|
||||
} while ((l_iter = l_iter->next) != l_first);
|
||||
|
||||
/* Copy Custom Data */
|
||||
CustomData_to_bmesh_block(&mesh_pdata, &bm->pdata, i, &f->head.data, true);
|
||||
mesh_attributes_copy_to_bmesh_block(bm->pdata, poly_info, i, f->head);
|
||||
|
||||
if (params->calc_face_normal) {
|
||||
BM_face_normal_update(f);
|
||||
|
@ -998,6 +1059,66 @@ static void convert_bmesh_selection_flags_to_mesh_attributes(BMesh &bm,
|
|||
}
|
||||
}
|
||||
|
||||
struct BMeshToMeshLayerInfo {
|
||||
eCustomDataType type;
|
||||
/** The layer's position in the BMesh element's data block. */
|
||||
int bmesh_offset;
|
||||
/** The mesh's #CustomDataLayer::data. When null, the BMesh block is set to its default value. */
|
||||
void *mesh_data;
|
||||
/** The size of every custom data element. */
|
||||
size_t elem_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate the necessary information to copy every data layer from the BMesh to the Mesh.
|
||||
*/
|
||||
static Vector<BMeshToMeshLayerInfo> bm_to_mesh_copy_info_calc(const CustomData &bm_data,
|
||||
CustomData &mesh_data)
|
||||
{
|
||||
Vector<BMeshToMeshLayerInfo> infos;
|
||||
std::array<int, CD_NUMTYPES> per_type_index;
|
||||
per_type_index.fill(0);
|
||||
for (const int i : IndexRange(mesh_data.totlayer)) {
|
||||
const CustomDataLayer &mesh_layer = mesh_data.layers[i];
|
||||
const eCustomDataType type = eCustomDataType(mesh_layer.type);
|
||||
const int bm_layer_index =
|
||||
mesh_layer.name[0] == '\0' ?
|
||||
CustomData_get_layer_index_n(&bm_data, type, per_type_index[type]) :
|
||||
CustomData_get_named_layer_index(&bm_data, type, mesh_layer.name);
|
||||
|
||||
/* Skip layers that don't exist in `bm_data` or are explicitly set to not be
|
||||
* copied. The layers are either set separately or shouldn't exist on the mesh. */
|
||||
if (bm_layer_index == -1) {
|
||||
continue;
|
||||
}
|
||||
const CustomDataLayer &bm_layer = bm_data.layers[bm_layer_index];
|
||||
if (bm_layer.flag & CD_FLAG_NOCOPY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BMeshToMeshLayerInfo info{};
|
||||
info.type = type;
|
||||
info.bmesh_offset = bm_layer.offset;
|
||||
info.mesh_data = mesh_layer.data;
|
||||
info.elem_size = CustomData_get_elem_size(&mesh_layer);
|
||||
infos.append(info);
|
||||
|
||||
per_type_index[type]++;
|
||||
}
|
||||
return infos;
|
||||
}
|
||||
|
||||
static void bmesh_block_copy_to_mesh_attributes(const Span<BMeshToMeshLayerInfo> copy_info,
|
||||
const int mesh_index,
|
||||
const void *block)
|
||||
{
|
||||
for (const BMeshToMeshLayerInfo &info : copy_info) {
|
||||
CustomData_data_copy_value(info.type,
|
||||
POINTER_OFFSET(block, info.bmesh_offset),
|
||||
POINTER_OFFSET(info.mesh_data, info.elem_size * mesh_index));
|
||||
}
|
||||
}
|
||||
|
||||
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params)
|
||||
{
|
||||
using namespace blender;
|
||||
|
@ -1011,6 +1132,8 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
|
|||
|
||||
const int ototvert = me->totvert;
|
||||
|
||||
blender::Vector<int> ldata_layers_marked_nocopy;
|
||||
|
||||
/* Free custom data. */
|
||||
CustomData_free(&me->vdata, me->totvert);
|
||||
CustomData_free(&me->edata, me->totedge);
|
||||
|
@ -1041,9 +1164,17 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
|
|||
&bm->ldata, CD_PROP_BOOL, BKE_uv_map_edge_select_name_get(layer_name, sub_layer_name));
|
||||
int pin_layer_index = CustomData_get_named_layer_index(
|
||||
&bm->ldata, CD_PROP_BOOL, BKE_uv_map_pin_name_get(layer_name, sub_layer_name));
|
||||
int vertsel_offset = bm->ldata.layers[vertsel_layer_index].offset;
|
||||
int edgesel_offset = bm->ldata.layers[edgesel_layer_index].offset;
|
||||
int pin_offset = bm->ldata.layers[pin_layer_index].offset;
|
||||
|
||||
/* If ever the uv map associated bool layers become optional in BMesh as well (like in Mesh)
|
||||
* this assert needs to be removed. For now it is a bug if they don't exist. */
|
||||
BLI_assert(vertsel_layer_index >= 0 && edgesel_layer_index >= 0 && pin_layer_index >= 0);
|
||||
|
||||
int vertsel_offset = vertsel_layer_index >= 0 ? bm->ldata.layers[vertsel_layer_index].offset :
|
||||
-1;
|
||||
int edgesel_offset = edgesel_layer_index >= 0 ? bm->ldata.layers[edgesel_layer_index].offset :
|
||||
-1;
|
||||
int pin_offset = pin_layer_index >= 0 ? bm->ldata.layers[pin_layer_index].offset : -1;
|
||||
|
||||
bool need_vertsel = false;
|
||||
bool need_edgesel = false;
|
||||
bool need_pin = false;
|
||||
|
@ -1051,10 +1182,20 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
|
|||
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
||||
BMIter liter;
|
||||
BMLoop *l;
|
||||
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
|
||||
need_vertsel |= BM_ELEM_CD_GET_BOOL(l, vertsel_offset);
|
||||
need_edgesel |= BM_ELEM_CD_GET_BOOL(l, edgesel_offset);
|
||||
need_pin |= BM_ELEM_CD_GET_BOOL(l, pin_offset);
|
||||
if (vertsel_layer_index >= 0) {
|
||||
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
|
||||
need_vertsel |= BM_ELEM_CD_GET_BOOL(l, vertsel_offset);
|
||||
}
|
||||
}
|
||||
if (edgesel_layer_index >= 0) {
|
||||
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
|
||||
need_edgesel |= BM_ELEM_CD_GET_BOOL(l, edgesel_offset);
|
||||
}
|
||||
}
|
||||
if (pin_layer_index) {
|
||||
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
|
||||
need_pin |= BM_ELEM_CD_GET_BOOL(l, pin_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1063,18 +1204,21 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
|
|||
}
|
||||
else {
|
||||
bm->ldata.layers[vertsel_layer_index].flag |= CD_FLAG_NOCOPY;
|
||||
ldata_layers_marked_nocopy.append(vertsel_layer_index);
|
||||
}
|
||||
if (need_edgesel) {
|
||||
bm->ldata.layers[edgesel_layer_index].flag &= ~CD_FLAG_NOCOPY;
|
||||
}
|
||||
else {
|
||||
bm->ldata.layers[edgesel_layer_index].flag |= CD_FLAG_NOCOPY;
|
||||
ldata_layers_marked_nocopy.append(edgesel_layer_index);
|
||||
}
|
||||
if (need_pin) {
|
||||
bm->ldata.layers[pin_layer_index].flag &= ~CD_FLAG_NOCOPY;
|
||||
}
|
||||
else {
|
||||
bm->ldata.layers[pin_layer_index].flag |= CD_FLAG_NOCOPY;
|
||||
ldata_layers_marked_nocopy.append(pin_layer_index);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1087,6 +1231,16 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
|
|||
CustomData_copy(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly);
|
||||
}
|
||||
|
||||
const Vector<BMeshToMeshLayerInfo> vert_info = bm_to_mesh_copy_info_calc(bm->vdata, me->vdata);
|
||||
const Vector<BMeshToMeshLayerInfo> edge_info = bm_to_mesh_copy_info_calc(bm->edata, me->edata);
|
||||
const Vector<BMeshToMeshLayerInfo> poly_info = bm_to_mesh_copy_info_calc(bm->pdata, me->pdata);
|
||||
const Vector<BMeshToMeshLayerInfo> loop_info = bm_to_mesh_copy_info_calc(bm->ldata, me->ldata);
|
||||
|
||||
/* Clear the CD_FLAG_NOCOPY flags for the layers they were temporarily set on */
|
||||
for (const int i : ldata_layers_marked_nocopy) {
|
||||
bm->ldata.layers[i].flag &= ~CD_FLAG_NOCOPY;
|
||||
}
|
||||
|
||||
CustomData_add_layer_named(
|
||||
&me->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, nullptr, me->totvert, "position");
|
||||
CustomData_add_layer(&me->edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, me->totedge);
|
||||
|
@ -1119,8 +1273,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
|
|||
|
||||
BM_elem_index_set(v, i); /* set_inline */
|
||||
|
||||
/* Copy over custom-data. */
|
||||
CustomData_from_bmesh_block(&bm->vdata, &me->vdata, v->head.data, i);
|
||||
bmesh_block_copy_to_mesh_attributes(vert_info, i, v->head.data);
|
||||
|
||||
i++;
|
||||
|
||||
|
@ -1146,8 +1299,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
|
|||
|
||||
BM_elem_index_set(e, i); /* set_inline */
|
||||
|
||||
/* Copy over custom-data. */
|
||||
CustomData_from_bmesh_block(&bm->edata, &me->edata, e->head.data, i);
|
||||
bmesh_block_copy_to_mesh_attributes(edge_info, i, e->head.data);
|
||||
|
||||
i++;
|
||||
BM_CHECK_ELEMENT(e);
|
||||
|
@ -1176,8 +1328,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
|
|||
mloop[j].e = BM_elem_index_get(l_iter->e);
|
||||
mloop[j].v = BM_elem_index_get(l_iter->v);
|
||||
|
||||
/* Copy over custom-data. */
|
||||
CustomData_from_bmesh_block(&bm->ldata, &me->ldata, l_iter->head.data, j);
|
||||
bmesh_block_copy_to_mesh_attributes(loop_info, j, l_iter->head.data);
|
||||
|
||||
j++;
|
||||
BM_CHECK_ELEMENT(l_iter);
|
||||
|
@ -1189,8 +1340,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
|
|||
me->act_face = i;
|
||||
}
|
||||
|
||||
/* Copy over custom-data. */
|
||||
CustomData_from_bmesh_block(&bm->pdata, &me->pdata, f->head.data, i);
|
||||
bmesh_block_copy_to_mesh_attributes(poly_info, i, f->head.data);
|
||||
|
||||
i++;
|
||||
BM_CHECK_ELEMENT(f);
|
||||
|
@ -1399,12 +1549,13 @@ static void bm_to_mesh_verts(const BMesh &bm,
|
|||
MutableSpan<bool> select_vert,
|
||||
MutableSpan<bool> hide_vert)
|
||||
{
|
||||
const Vector<BMeshToMeshLayerInfo> info = bm_to_mesh_copy_info_calc(bm.vdata, mesh.vdata);
|
||||
MutableSpan<float3> dst_vert_positions = mesh.vert_positions_for_write();
|
||||
threading::parallel_for(dst_vert_positions.index_range(), 1024, [&](const IndexRange range) {
|
||||
for (const int vert_i : range) {
|
||||
const BMVert &src_vert = *bm_verts[vert_i];
|
||||
copy_v3_v3(dst_vert_positions[vert_i], src_vert.co);
|
||||
CustomData_from_bmesh_block(&bm.vdata, &mesh.vdata, src_vert.head.data, vert_i);
|
||||
bmesh_block_copy_to_mesh_attributes(info, vert_i, src_vert.head.data);
|
||||
}
|
||||
if (!select_vert.is_empty()) {
|
||||
for (const int vert_i : range) {
|
||||
|
@ -1426,6 +1577,7 @@ static void bm_to_mesh_edges(const BMesh &bm,
|
|||
MutableSpan<bool> hide_edge,
|
||||
MutableSpan<bool> sharp_edge)
|
||||
{
|
||||
const Vector<BMeshToMeshLayerInfo> info = bm_to_mesh_copy_info_calc(bm.edata, mesh.edata);
|
||||
MutableSpan<MEdge> dst_edges = mesh.edges_for_write();
|
||||
threading::parallel_for(dst_edges.index_range(), 512, [&](const IndexRange range) {
|
||||
for (const int edge_i : range) {
|
||||
|
@ -1434,7 +1586,7 @@ static void bm_to_mesh_edges(const BMesh &bm,
|
|||
dst_edge.v1 = BM_elem_index_get(src_edge.v1);
|
||||
dst_edge.v2 = BM_elem_index_get(src_edge.v2);
|
||||
dst_edge.flag = bm_edge_flag_to_mflag(&src_edge);
|
||||
CustomData_from_bmesh_block(&bm.edata, &mesh.edata, src_edge.head.data, edge_i);
|
||||
bmesh_block_copy_to_mesh_attributes(info, edge_i, src_edge.head.data);
|
||||
}
|
||||
if (!select_edge.is_empty()) {
|
||||
for (const int edge_i : range) {
|
||||
|
@ -1461,6 +1613,7 @@ static void bm_to_mesh_faces(const BMesh &bm,
|
|||
MutableSpan<bool> hide_poly,
|
||||
MutableSpan<int> material_indices)
|
||||
{
|
||||
const Vector<BMeshToMeshLayerInfo> info = bm_to_mesh_copy_info_calc(bm.pdata, mesh.pdata);
|
||||
MutableSpan<MPoly> dst_polys = mesh.polys_for_write();
|
||||
threading::parallel_for(dst_polys.index_range(), 1024, [&](const IndexRange range) {
|
||||
for (const int face_i : range) {
|
||||
|
@ -1469,7 +1622,7 @@ static void bm_to_mesh_faces(const BMesh &bm,
|
|||
dst_poly.totloop = src_face.len;
|
||||
dst_poly.loopstart = BM_elem_index_get(BM_FACE_FIRST_LOOP(&src_face));
|
||||
dst_poly.flag = bm_face_flag_to_mflag(&src_face);
|
||||
CustomData_from_bmesh_block(&bm.pdata, &mesh.pdata, src_face.head.data, face_i);
|
||||
bmesh_block_copy_to_mesh_attributes(info, face_i, src_face.head.data);
|
||||
}
|
||||
if (!select_poly.is_empty()) {
|
||||
for (const int face_i : range) {
|
||||
|
@ -1491,6 +1644,7 @@ static void bm_to_mesh_faces(const BMesh &bm,
|
|||
|
||||
static void bm_to_mesh_loops(const BMesh &bm, const Span<const BMLoop *> bm_loops, Mesh &mesh)
|
||||
{
|
||||
const Vector<BMeshToMeshLayerInfo> info = bm_to_mesh_copy_info_calc(bm.ldata, mesh.ldata);
|
||||
MutableSpan<MLoop> dst_loops = mesh.loops_for_write();
|
||||
threading::parallel_for(dst_loops.index_range(), 1024, [&](const IndexRange range) {
|
||||
for (const int loop_i : range) {
|
||||
|
@ -1498,7 +1652,7 @@ static void bm_to_mesh_loops(const BMesh &bm, const Span<const BMLoop *> bm_loop
|
|||
MLoop &dst_loop = dst_loops[loop_i];
|
||||
dst_loop.v = BM_elem_index_get(src_loop.v);
|
||||
dst_loop.e = BM_elem_index_get(src_loop.e);
|
||||
CustomData_from_bmesh_block(&bm.ldata, &mesh.ldata, src_loop.head.data, loop_i);
|
||||
bmesh_block_copy_to_mesh_attributes(info, loop_i, src_loop.head.data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1197,8 +1197,8 @@ static void bmw_FaceLoopWalker_begin(BMWalker *walker, void *data)
|
|||
{
|
||||
BMwFaceLoopWalker *lwalk, owalk, *owalk_pt;
|
||||
BMEdge *e = data;
|
||||
/* BMesh *bm = walker->bm; */ /* UNUSED */
|
||||
/* int fcount = BM_edge_face_count(e); */ /* UNUSED */
|
||||
// BMesh *bm = walker->bm; /* UNUSED */
|
||||
// int fcount = BM_edge_face_count(e); /* UNUSED */
|
||||
|
||||
if (!bmw_FaceLoopWalker_edge_begins_loop(walker, e)) {
|
||||
return;
|
||||
|
|
|
@ -1183,7 +1183,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
|
|||
f = BM_face_create_verts(bm, varr, j, es->l->f, BM_CREATE_NOP, true);
|
||||
BMO_face_flag_enable(bm, f, ELE_NEW);
|
||||
|
||||
/* Copy for loop data, otherwise UVs and vcols are no good.
|
||||
/* Copy for loop data, otherwise UVs and vertex-colors are no good.
|
||||
* tiny speedup here we could be more clever and copy from known adjacent data
|
||||
* also - we could attempt to interpolate the loop data,
|
||||
* this would be much slower but more useful too. */
|
||||
|
|
|
@ -41,10 +41,10 @@ static float *parallel_reduction_dispatch(Context &context,
|
|||
GPUTexture *reduced_texture = context.texture_pool().acquire(reduced_size, format);
|
||||
|
||||
GPU_memory_barrier(GPU_BARRIER_TEXTURE_FETCH);
|
||||
const int texture_image_unit = GPU_shader_get_texture_binding(shader, "input_tx");
|
||||
const int texture_image_unit = GPU_shader_get_sampler_binding(shader, "input_tx");
|
||||
GPU_texture_bind(texture_to_reduce, texture_image_unit);
|
||||
|
||||
const int image_unit = GPU_shader_get_texture_binding(shader, "output_img");
|
||||
const int image_unit = GPU_shader_get_sampler_binding(shader, "output_img");
|
||||
GPU_texture_image_bind(reduced_texture, image_unit);
|
||||
|
||||
GPU_compute_dispatch(shader, reduced_size.x, reduced_size.y, 1);
|
||||
|
|
|
@ -135,7 +135,7 @@ void MorphologicalDistanceFeatherWeights::compute_distance_falloffs(int type, in
|
|||
void MorphologicalDistanceFeatherWeights::bind_weights_as_texture(GPUShader *shader,
|
||||
const char *texture_name) const
|
||||
{
|
||||
const int texture_image_unit = GPU_shader_get_texture_binding(shader, texture_name);
|
||||
const int texture_image_unit = GPU_shader_get_sampler_binding(shader, texture_name);
|
||||
GPU_texture_bind(weights_texture_, texture_image_unit);
|
||||
}
|
||||
|
||||
|
@ -147,7 +147,7 @@ void MorphologicalDistanceFeatherWeights::unbind_weights_as_texture() const
|
|||
void MorphologicalDistanceFeatherWeights::bind_distance_falloffs_as_texture(
|
||||
GPUShader *shader, const char *texture_name) const
|
||||
{
|
||||
const int texture_image_unit = GPU_shader_get_texture_binding(shader, texture_name);
|
||||
const int texture_image_unit = GPU_shader_get_sampler_binding(shader, texture_name);
|
||||
GPU_texture_bind(distance_falloffs_texture_, texture_image_unit);
|
||||
}
|
||||
|
||||
|
|
|
@ -103,7 +103,7 @@ SymmetricBlurWeights::~SymmetricBlurWeights()
|
|||
|
||||
void SymmetricBlurWeights::bind_as_texture(GPUShader *shader, const char *texture_name) const
|
||||
{
|
||||
const int texture_image_unit = GPU_shader_get_texture_binding(shader, texture_name);
|
||||
const int texture_image_unit = GPU_shader_get_sampler_binding(shader, texture_name);
|
||||
GPU_texture_bind(texture_, texture_image_unit);
|
||||
}
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ SymmetricSeparableBlurWeights::~SymmetricSeparableBlurWeights()
|
|||
void SymmetricSeparableBlurWeights::bind_as_texture(GPUShader *shader,
|
||||
const char *texture_name) const
|
||||
{
|
||||
const int texture_image_unit = GPU_shader_get_texture_binding(shader, texture_name);
|
||||
const int texture_image_unit = GPU_shader_get_sampler_binding(shader, texture_name);
|
||||
GPU_texture_bind(texture_, texture_image_unit);
|
||||
}
|
||||
|
||||
|
|
|
@ -161,7 +161,7 @@ void Evaluator::compile_and_evaluate_shader_compile_unit(CompileState &compile_s
|
|||
void Evaluator::map_shader_operation_inputs_to_their_results(ShaderOperation *operation,
|
||||
CompileState &compile_state)
|
||||
{
|
||||
for (const auto &item : operation->get_inputs_to_linked_outputs_map().items()) {
|
||||
for (const auto item : operation->get_inputs_to_linked_outputs_map().items()) {
|
||||
Result &result = compile_state.get_result_from_output_socket(item.value);
|
||||
operation->map_input_to_result(item.key, &result);
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ void Result::bind_as_texture(GPUShader *shader, const char *texture_name) const
|
|||
/* Make sure any prior writes to the texture are reflected before reading from it. */
|
||||
GPU_memory_barrier(GPU_BARRIER_TEXTURE_FETCH);
|
||||
|
||||
const int texture_image_unit = GPU_shader_get_texture_binding(shader, texture_name);
|
||||
const int texture_image_unit = GPU_shader_get_sampler_binding(shader, texture_name);
|
||||
GPU_texture_bind(texture_, texture_image_unit);
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ void Result::bind_as_image(GPUShader *shader, const char *image_name, bool read)
|
|||
GPU_memory_barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
|
||||
}
|
||||
|
||||
const int image_unit = GPU_shader_get_texture_binding(shader, image_name);
|
||||
const int image_unit = GPU_shader_get_sampler_binding(shader, image_name);
|
||||
GPU_texture_image_bind(texture_, image_unit);
|
||||
}
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ Map<std::string, DOutputSocket> &ShaderOperation::get_inputs_to_linked_outputs_m
|
|||
|
||||
void ShaderOperation::compute_results_reference_counts(const Schedule &schedule)
|
||||
{
|
||||
for (const auto &item : output_sockets_to_output_identifiers_map_.items()) {
|
||||
for (const auto item : output_sockets_to_output_identifiers_map_.items()) {
|
||||
const int reference_count = number_of_inputs_linked_to_output_conditioned(
|
||||
item.key, [&](DInputSocket input) { return schedule.contains(input.node()); });
|
||||
|
||||
|
@ -95,14 +95,14 @@ void ShaderOperation::bind_material_resources(GPUShader *shader)
|
|||
* no uniforms. */
|
||||
GPUUniformBuf *ubo = GPU_material_uniform_buffer_get(material_);
|
||||
if (ubo) {
|
||||
GPU_uniformbuf_bind(ubo, GPU_shader_get_uniform_block_binding(shader, GPU_UBO_BLOCK_NAME));
|
||||
GPU_uniformbuf_bind(ubo, GPU_shader_get_ubo_binding(shader, GPU_UBO_BLOCK_NAME));
|
||||
}
|
||||
|
||||
/* Bind color band textures needed by curve and ramp nodes. */
|
||||
ListBase textures = GPU_material_textures(material_);
|
||||
LISTBASE_FOREACH (GPUMaterialTexture *, texture, &textures) {
|
||||
if (texture->colorband) {
|
||||
const int texture_image_unit = GPU_shader_get_texture_binding(shader, texture->sampler_name);
|
||||
const int texture_image_unit = GPU_shader_get_sampler_binding(shader, texture->sampler_name);
|
||||
GPU_texture_bind(*texture->colorband, texture_image_unit);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -225,7 +225,7 @@ set(SRC
|
|||
DRW_select_buffer.h
|
||||
intern/DRW_gpu_wrapper.hh
|
||||
intern/DRW_render.h
|
||||
intern/draw_attributes.h
|
||||
intern/draw_attributes.hh
|
||||
intern/draw_cache.h
|
||||
intern/draw_cache_extract.hh
|
||||
intern/draw_cache_impl.h
|
||||
|
@ -234,7 +234,7 @@ set(SRC
|
|||
intern/draw_command.hh
|
||||
intern/draw_common.h
|
||||
intern/draw_common_shader_shared.h
|
||||
intern/draw_curves_private.h
|
||||
intern/draw_curves_private.hh
|
||||
intern/draw_debug.h
|
||||
intern/draw_debug.hh
|
||||
intern/draw_hair_private.h
|
||||
|
@ -702,6 +702,7 @@ set(GLSL_SRC
|
|||
engines/overlay/shaders/overlay_point_varying_color_frag.glsl
|
||||
engines/overlay/shaders/overlay_point_varying_color_varying_outline_aa_frag.glsl
|
||||
engines/overlay/shaders/overlay_pointcloud_only_vert.glsl
|
||||
engines/overlay/shaders/overlay_sculpt_curves_cage_vert.glsl
|
||||
engines/overlay/shaders/overlay_sculpt_curves_selection_frag.glsl
|
||||
engines/overlay/shaders/overlay_sculpt_curves_selection_vert.glsl
|
||||
engines/overlay/shaders/overlay_sculpt_mask_frag.glsl
|
||||
|
|
|
@ -197,6 +197,7 @@ void DRW_gpu_render_context_enable(void *re_gpu_context);
|
|||
void DRW_gpu_render_context_disable(void *re_gpu_context);
|
||||
|
||||
void DRW_deferred_shader_remove(struct GPUMaterial *mat);
|
||||
void DRW_deferred_shader_optimize_remove(struct GPUMaterial *mat);
|
||||
|
||||
/**
|
||||
* Get DrawData from the given ID-block. In order for this to work, we assume that
|
||||
|
|
|
@ -53,6 +53,7 @@ static void eevee_engine_init(void *ved)
|
|||
stl->g_data->valid_double_buffer = (txl->color_double_buffer != NULL);
|
||||
stl->g_data->valid_taa_history = (txl->taa_history != NULL);
|
||||
stl->g_data->queued_shaders_count = 0;
|
||||
stl->g_data->queued_optimise_shaders_count = 0;
|
||||
stl->g_data->render_timesteps = 1;
|
||||
stl->g_data->disable_ligthprobes = v3d &&
|
||||
(v3d->object_type_exclude_viewport & (1 << OB_LIGHTPROBE));
|
||||
|
@ -178,6 +179,11 @@ static void eevee_cache_finish(void *vedata)
|
|||
if (g_data->queued_shaders_count > 0) {
|
||||
SNPRINTF(ved->info, TIP_("Compiling Shaders (%d remaining)"), g_data->queued_shaders_count);
|
||||
}
|
||||
else if (g_data->queued_optimise_shaders_count > 0) {
|
||||
SNPRINTF(ved->info,
|
||||
TIP_("Optimizing Shaders (%d remaining)"),
|
||||
g_data->queued_optimise_shaders_count);
|
||||
}
|
||||
}
|
||||
|
||||
/* As renders in an HDR off-screen buffer, we need draw everything once
|
||||
|
|
|
@ -1000,6 +1000,8 @@ typedef struct EEVEE_PrivateData {
|
|||
/* Compiling shaders count. This is to track if a shader has finished compiling. */
|
||||
int queued_shaders_count;
|
||||
int queued_shaders_count_prev;
|
||||
/* Optimizing shaders count. */
|
||||
int queued_optimise_shaders_count;
|
||||
|
||||
/* LookDev Settings */
|
||||
int studiolight_index;
|
||||
|
|
|
@ -1390,12 +1390,21 @@ struct GPUMaterial *EEVEE_material_get(
|
|||
return nullptr;
|
||||
}
|
||||
switch (status) {
|
||||
case GPU_MAT_SUCCESS:
|
||||
break;
|
||||
case GPU_MAT_QUEUED:
|
||||
case GPU_MAT_SUCCESS: {
|
||||
/* Determine optimization status for remaining compilations counter. */
|
||||
int optimization_status = GPU_material_optimization_status(mat);
|
||||
if (optimization_status == GPU_MAT_OPTIMIZATION_QUEUED) {
|
||||
vedata->stl->g_data->queued_optimise_shaders_count++;
|
||||
}
|
||||
} break;
|
||||
case GPU_MAT_QUEUED: {
|
||||
vedata->stl->g_data->queued_shaders_count++;
|
||||
mat = EEVEE_material_default_get(scene, ma, options);
|
||||
break;
|
||||
GPUMaterial *default_mat = EEVEE_material_default_get(scene, ma, options);
|
||||
/* Mark pending material with its default material for future cache warming.*/
|
||||
GPU_material_set_default(mat, default_mat);
|
||||
/* Return default material. */
|
||||
mat = default_mat;
|
||||
} break;
|
||||
case GPU_MAT_FAILED:
|
||||
default:
|
||||
ma = EEVEE_material_default_error_get();
|
||||
|
|
|
@ -507,6 +507,8 @@ GPUMaterial *ShaderModule::material_shader_get(const char *name,
|
|||
this);
|
||||
GPU_material_status_set(gpumat, GPU_MAT_QUEUED);
|
||||
GPU_material_compile(gpumat);
|
||||
/* Queue deferred material optimization. */
|
||||
DRW_shader_queue_optimize_material(gpumat);
|
||||
return gpumat;
|
||||
}
|
||||
|
||||
|
|
|
@ -409,7 +409,7 @@ void ShadowDirectional::cascade_tilemaps_distribution(Light &light, const Camera
|
|||
|
||||
/* Offset in tiles from the origin to the center of the first tile-maps. */
|
||||
int2 origin_offset = int2(round(float2(near_point) / tile_size));
|
||||
/* Offset in tiles between the first andlod the last tile-maps. */
|
||||
/* Offset in tiles between the first and the last tile-maps. */
|
||||
int2 offset_vector = int2(round(farthest_tilemap_center / tile_size));
|
||||
|
||||
light.clipmap_base_offset = (offset_vector * (1 << 16)) / max_ii(levels_range.size() - 1, 1);
|
||||
|
|
|
@ -21,8 +21,7 @@ void main()
|
|||
float light_count = 0.0;
|
||||
uint light_cull = 0u;
|
||||
vec2 px = gl_FragCoord.xy;
|
||||
LIGHT_FOREACH_BEGIN_LOCAL(light_cull_buf, light_zbin_buf, light_tile_buf, px, vP_z, l_idx)
|
||||
{
|
||||
LIGHT_FOREACH_BEGIN_LOCAL (light_cull_buf, light_zbin_buf, light_tile_buf, px, vP_z, l_idx) {
|
||||
LightData light = light_buf[l_idx];
|
||||
light_cull |= 1u << l_idx;
|
||||
light_count += 1.0;
|
||||
|
|
|
@ -192,4 +192,4 @@ void main()
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,4 +38,4 @@ void main()
|
|||
}
|
||||
tile_start += lod_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,4 +126,4 @@ void main()
|
|||
clear_dispatch_buf.num_groups_x = pages_infos_buf.page_size / SHADOW_PAGE_CLEAR_GROUP_SIZE;
|
||||
clear_dispatch_buf.num_groups_y = pages_infos_buf.page_size / SHADOW_PAGE_CLEAR_GROUP_SIZE;
|
||||
clear_dispatch_buf.num_groups_z = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,4 +51,4 @@ void main()
|
|||
}
|
||||
tile_start += lod_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,4 +52,4 @@ void main()
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,4 +91,4 @@ void main()
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,4 +29,4 @@ void main()
|
|||
vec2 pixel = vec2(gl_GlobalInvocationID.xy);
|
||||
|
||||
shadow_tag_usage(vP, P, pixel);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
void main()
|
||||
{
|
||||
shadow_tag_usage(interp.vP, interp.P, gl_FragCoord.xy);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,4 +101,4 @@ void shadow_tag_usage(vec3 vP, vec3 P, vec2 pixel)
|
|||
shadow_tag_usage_tilemap(l_idx, P, dist_to_cam, false);
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,4 +19,4 @@ void main()
|
|||
interp.vP = point_world_to_view(interp.P);
|
||||
|
||||
gl_Position = point_world_to_ndc(interp.P);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -395,4 +395,4 @@ void main()
|
|||
EXPECT_NEAR(shadow_slope_bias_get(atlas_size, light, lNg, lP0, vec2(0.0), 2), 0.0, 1e-4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,4 +74,4 @@ void main()
|
|||
* thread 0. */
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
}
|
||||
}
|
||||
|
|
|
@ -178,4 +178,4 @@ void main()
|
|||
/* Clamp it as it can underflow if there is too much tile present on screen. */
|
||||
pages_infos_buf.page_free_count = max(pages_infos_buf.page_free_count, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,4 +90,4 @@ void main()
|
|||
tiles_buf[tile_store] = tile;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "eevee_defines.hh"
|
||||
|
||||
|
|
|
@ -5,10 +5,14 @@
|
|||
* \ingroup draw_engine
|
||||
*/
|
||||
|
||||
#include "BKE_curves.h"
|
||||
|
||||
#include "DRW_render.h"
|
||||
|
||||
#include "ED_view3d.h"
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
#include "draw_cache_impl.h"
|
||||
|
||||
#include "overlay_private.hh"
|
||||
|
@ -17,7 +21,10 @@ void OVERLAY_edit_curves_init(OVERLAY_Data *vedata)
|
|||
{
|
||||
OVERLAY_PrivateData *pd = vedata->stl->pd;
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
const Object *obact_orig = DEG_get_original_object(draw_ctx->obact);
|
||||
|
||||
const Curves &curves_id = *static_cast<const Curves *>(obact_orig->data);
|
||||
pd->edit_curves.do_points = curves_id.selection_domain == ATTR_DOMAIN_POINT;
|
||||
pd->edit_curves.do_zbufclip = XRAY_FLAG_ENABLED(draw_ctx->v3d);
|
||||
|
||||
/* Create view with depth offset. */
|
||||
|
@ -39,10 +46,12 @@ void OVERLAY_edit_curves_cache_init(OVERLAY_Data *vedata)
|
|||
|
||||
/* Run Twice for in-front passes. */
|
||||
for (int i = 0; i < 2; i++) {
|
||||
DRW_PASS_CREATE(psl->edit_curves_points_ps[i], (state | pd->clipping_state));
|
||||
sh = OVERLAY_shader_edit_particle_point();
|
||||
grp = pd->edit_curves_points_grp[i] = DRW_shgroup_create(sh, psl->edit_curves_points_ps[i]);
|
||||
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
|
||||
if (pd->edit_curves.do_points) {
|
||||
DRW_PASS_CREATE(psl->edit_curves_points_ps[i], (state | pd->clipping_state));
|
||||
sh = OVERLAY_shader_edit_particle_point();
|
||||
grp = pd->edit_curves_points_grp[i] = DRW_shgroup_create(sh, psl->edit_curves_points_ps[i]);
|
||||
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
|
||||
}
|
||||
|
||||
DRW_PASS_CREATE(psl->edit_curves_lines_ps[i], (state | pd->clipping_state));
|
||||
sh = OVERLAY_shader_edit_particle_strand();
|
||||
|
@ -56,9 +65,11 @@ static void overlay_edit_curves_add_ob_to_pass(OVERLAY_PrivateData *pd, Object *
|
|||
{
|
||||
Curves *curves = static_cast<Curves *>(ob->data);
|
||||
|
||||
DRWShadingGroup *point_shgrp = pd->edit_curves_points_grp[in_front];
|
||||
struct GPUBatch *geom_points = DRW_curves_batch_cache_get_edit_points(curves);
|
||||
DRW_shgroup_call_no_cull(point_shgrp, geom_points, ob);
|
||||
if (pd->edit_curves.do_points) {
|
||||
DRWShadingGroup *point_shgrp = pd->edit_curves_points_grp[in_front];
|
||||
struct GPUBatch *geom_points = DRW_curves_batch_cache_get_edit_points(curves);
|
||||
DRW_shgroup_call_no_cull(point_shgrp, geom_points, ob);
|
||||
}
|
||||
|
||||
DRWShadingGroup *lines_shgrp = pd->edit_curves_lines_grp[in_front];
|
||||
struct GPUBatch *geom_lines = DRW_curves_batch_cache_get_edit_lines(curves);
|
||||
|
@ -89,12 +100,16 @@ void OVERLAY_edit_curves_draw(OVERLAY_Data *vedata)
|
|||
|
||||
if (pd->edit_curves.do_zbufclip) {
|
||||
DRW_view_set_active(pd->view_edit_curves);
|
||||
DRW_draw_pass(psl->edit_curves_points_ps[NOT_IN_FRONT]);
|
||||
if (pd->edit_curves.do_points) {
|
||||
DRW_draw_pass(psl->edit_curves_points_ps[NOT_IN_FRONT]);
|
||||
}
|
||||
DRW_draw_pass(psl->edit_curves_lines_ps[NOT_IN_FRONT]);
|
||||
}
|
||||
else {
|
||||
DRW_view_set_active(pd->view_edit_curves);
|
||||
DRW_draw_pass(psl->edit_curves_points_ps[IN_FRONT]);
|
||||
if (pd->edit_curves.do_points) {
|
||||
DRW_draw_pass(psl->edit_curves_points_ps[IN_FRONT]);
|
||||
}
|
||||
DRW_draw_pass(psl->edit_curves_lines_ps[IN_FRONT]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -632,6 +632,10 @@ static void OVERLAY_draw_scene(void *vedata)
|
|||
GPU_framebuffer_bind(fbl->overlay_line_fb);
|
||||
}
|
||||
|
||||
if (pd->ctx_mode == CTX_MODE_SCULPT_CURVES) {
|
||||
OVERLAY_sculpt_curves_draw_wires(data);
|
||||
}
|
||||
|
||||
OVERLAY_wireframe_draw(data);
|
||||
OVERLAY_armature_draw(data);
|
||||
OVERLAY_particle_draw(data);
|
||||
|
|
|
@ -120,6 +120,7 @@ typedef struct OVERLAY_PassList {
|
|||
DRWPass *pointcloud_ps;
|
||||
DRWPass *sculpt_mask_ps;
|
||||
DRWPass *sculpt_curves_selection_ps;
|
||||
DRWPass *sculpt_curves_cage_ps;
|
||||
DRWPass *volume_ps;
|
||||
DRWPass *wireframe_ps;
|
||||
DRWPass *wireframe_xray_ps;
|
||||
|
@ -287,6 +288,7 @@ typedef struct OVERLAY_PrivateData {
|
|||
DRWShadingGroup *pointcloud_dots_grp;
|
||||
DRWShadingGroup *sculpt_mask_grp;
|
||||
DRWShadingGroup *sculpt_curves_selection_grp;
|
||||
DRWShadingGroup *sculpt_curves_cage_lines_grp;
|
||||
DRWShadingGroup *viewer_attribute_curve_grp;
|
||||
DRWShadingGroup *viewer_attribute_curves_grp;
|
||||
DRWShadingGroup *viewer_attribute_mesh_grp;
|
||||
|
@ -362,6 +364,7 @@ typedef struct OVERLAY_PrivateData {
|
|||
int flag; /** Copy of #v3d->overlay.edit_flag. */
|
||||
} edit_mesh;
|
||||
struct {
|
||||
bool do_points;
|
||||
bool do_zbufclip;
|
||||
} edit_curves;
|
||||
struct {
|
||||
|
@ -686,6 +689,7 @@ void OVERLAY_sculpt_draw(OVERLAY_Data *vedata);
|
|||
void OVERLAY_sculpt_curves_cache_init(OVERLAY_Data *vedata);
|
||||
void OVERLAY_sculpt_curves_cache_populate(OVERLAY_Data *vedata, Object *ob);
|
||||
void OVERLAY_sculpt_curves_draw(OVERLAY_Data *vedata);
|
||||
void OVERLAY_sculpt_curves_draw_wires(OVERLAY_Data *vedata);
|
||||
|
||||
void OVERLAY_viewer_attribute_cache_init(OVERLAY_Data *vedata);
|
||||
void OVERLAY_viewer_attribute_cache_populate(OVERLAY_Data *vedata, Object *object);
|
||||
|
@ -775,6 +779,7 @@ GPUShader *OVERLAY_shader_particle_dot(void);
|
|||
GPUShader *OVERLAY_shader_particle_shape(void);
|
||||
GPUShader *OVERLAY_shader_sculpt_mask(void);
|
||||
GPUShader *OVERLAY_shader_sculpt_curves_selection(void);
|
||||
GPUShader *OVERLAY_shader_sculpt_curves_cage(void);
|
||||
GPUShader *OVERLAY_shader_viewer_attribute_curve(void);
|
||||
GPUShader *OVERLAY_shader_viewer_attribute_curves(void);
|
||||
GPUShader *OVERLAY_shader_viewer_attribute_mesh(void);
|
||||
|
|
|
@ -11,23 +11,41 @@
|
|||
#include "overlay_private.hh"
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_crazyspace.hh"
|
||||
#include "BKE_curves.hh"
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
void OVERLAY_sculpt_curves_cache_init(OVERLAY_Data *vedata)
|
||||
{
|
||||
OVERLAY_PassList *psl = vedata->psl;
|
||||
OVERLAY_PrivateData *pd = vedata->stl->pd;
|
||||
const View3DOverlay &overlay = vedata->stl->pd->overlay;
|
||||
|
||||
const DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
|
||||
DRW_PASS_CREATE(psl->sculpt_curves_selection_ps, state | pd->clipping_state);
|
||||
/* Selection overlay. */
|
||||
{
|
||||
const DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
|
||||
DRW_PASS_CREATE(psl->sculpt_curves_selection_ps, state | pd->clipping_state);
|
||||
|
||||
GPUShader *sh = OVERLAY_shader_sculpt_curves_selection();
|
||||
pd->sculpt_curves_selection_grp = DRW_shgroup_create(sh, psl->sculpt_curves_selection_ps);
|
||||
DRWShadingGroup *grp = pd->sculpt_curves_selection_grp;
|
||||
GPUShader *sh = OVERLAY_shader_sculpt_curves_selection();
|
||||
pd->sculpt_curves_selection_grp = DRW_shgroup_create(sh, psl->sculpt_curves_selection_ps);
|
||||
DRWShadingGroup *grp = pd->sculpt_curves_selection_grp;
|
||||
|
||||
/* Reuse the same mask opacity from sculpt mode, since it wasn't worth it to add a different
|
||||
* property yet. */
|
||||
DRW_shgroup_uniform_float_copy(grp, "selection_opacity", pd->overlay.sculpt_mode_mask_opacity);
|
||||
/* Reuse the same mask opacity from sculpt mode, since it wasn't worth it to add a different
|
||||
* property yet. */
|
||||
DRW_shgroup_uniform_float_copy(grp, "selection_opacity", pd->overlay.sculpt_mode_mask_opacity);
|
||||
}
|
||||
/* Cage overlay. */
|
||||
{
|
||||
const DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL |
|
||||
DRW_STATE_BLEND_ALPHA;
|
||||
DRW_PASS_CREATE(psl->sculpt_curves_cage_ps, state | pd->clipping_state);
|
||||
|
||||
GPUShader *sh = OVERLAY_shader_sculpt_curves_cage();
|
||||
pd->sculpt_curves_cage_lines_grp = DRW_shgroup_create(sh, psl->sculpt_curves_cage_ps);
|
||||
DRW_shgroup_uniform_float_copy(
|
||||
pd->sculpt_curves_cage_lines_grp, "opacity", overlay.sculpt_curves_cage_opacity);
|
||||
}
|
||||
}
|
||||
|
||||
static bool everything_selected(const Curves &curves_id)
|
||||
|
@ -39,7 +57,7 @@ static bool everything_selected(const Curves &curves_id)
|
|||
return selection.is_single() && selection.get_internal_single();
|
||||
}
|
||||
|
||||
void OVERLAY_sculpt_curves_cache_populate(OVERLAY_Data *vedata, Object *object)
|
||||
static void populate_selection_overlay(OVERLAY_Data *vedata, Object *object)
|
||||
{
|
||||
OVERLAY_PrivateData *pd = vedata->stl->pd;
|
||||
Curves *curves = static_cast<Curves *>(object->data);
|
||||
|
@ -68,16 +86,35 @@ void OVERLAY_sculpt_curves_cache_populate(OVERLAY_Data *vedata, Object *object)
|
|||
DRW_shgroup_buffer_texture(grp, "selection_tx", *texture);
|
||||
}
|
||||
|
||||
static void populate_edit_overlay(OVERLAY_Data *vedata, Object *object)
|
||||
{
|
||||
OVERLAY_PrivateData *pd = vedata->stl->pd;
|
||||
Curves *curves = static_cast<Curves *>(object->data);
|
||||
|
||||
GPUBatch *geom_lines = DRW_curves_batch_cache_get_edit_lines(curves);
|
||||
DRW_shgroup_call_no_cull(pd->sculpt_curves_cage_lines_grp, geom_lines, object);
|
||||
}
|
||||
|
||||
void OVERLAY_sculpt_curves_cache_populate(OVERLAY_Data *vedata, Object *object)
|
||||
{
|
||||
populate_selection_overlay(vedata, object);
|
||||
const View3DOverlay &overlay = vedata->stl->pd->overlay;
|
||||
if ((overlay.flag & V3D_OVERLAY_SCULPT_CURVES_CAGE) &&
|
||||
overlay.sculpt_curves_cage_opacity > 0.0f) {
|
||||
populate_edit_overlay(vedata, object);
|
||||
}
|
||||
}
|
||||
|
||||
void OVERLAY_sculpt_curves_draw(OVERLAY_Data *vedata)
|
||||
{
|
||||
OVERLAY_PassList *psl = vedata->psl;
|
||||
OVERLAY_PrivateData *pd = vedata->stl->pd;
|
||||
OVERLAY_FramebufferList *fbl = vedata->fbl;
|
||||
|
||||
if (DRW_state_is_fbo()) {
|
||||
GPU_framebuffer_bind(pd->painting.in_front ? fbl->overlay_in_front_fb :
|
||||
fbl->overlay_default_fb);
|
||||
}
|
||||
|
||||
DRW_draw_pass(psl->sculpt_curves_selection_ps);
|
||||
}
|
||||
|
||||
void OVERLAY_sculpt_curves_draw_wires(OVERLAY_Data *vedata)
|
||||
{
|
||||
OVERLAY_PassList *psl = vedata->psl;
|
||||
|
||||
DRW_draw_pass(psl->sculpt_curves_cage_ps);
|
||||
}
|
||||
|
|
|
@ -91,6 +91,7 @@ struct OVERLAY_Shaders {
|
|||
GPUShader *particle_shape;
|
||||
GPUShader *pointcloud_dot;
|
||||
GPUShader *sculpt_mask;
|
||||
GPUShader *sculpt_curves_cage;
|
||||
GPUShader *sculpt_curves_selection;
|
||||
GPUShader *uniform_color;
|
||||
GPUShader *uniform_color_pointcloud;
|
||||
|
@ -856,6 +857,18 @@ GPUShader *OVERLAY_shader_sculpt_curves_selection(void)
|
|||
return sh_data->sculpt_curves_selection;
|
||||
}
|
||||
|
||||
GPUShader *OVERLAY_shader_sculpt_curves_cage(void)
|
||||
{
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
|
||||
if (!sh_data->sculpt_curves_cage) {
|
||||
sh_data->sculpt_curves_cage = GPU_shader_create_from_info_name(
|
||||
(draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) ? "overlay_sculpt_curves_cage_clipped" :
|
||||
"overlay_sculpt_curves_cage");
|
||||
}
|
||||
return sh_data->sculpt_curves_cage;
|
||||
}
|
||||
|
||||
GPUShader *OVERLAY_shader_viewer_attribute_mesh(void)
|
||||
{
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
|
|
|
@ -496,7 +496,7 @@ GPU_SHADER_CREATE_INFO(overlay_edit_lattice_wire_clipped)
|
|||
GPU_SHADER_CREATE_INFO(overlay_edit_particle_strand)
|
||||
.do_static_compilation(true)
|
||||
.vertex_in(0, Type::VEC3, "pos")
|
||||
.vertex_in(1, Type::FLOAT, "color")
|
||||
.vertex_in(1, Type::FLOAT, "selection")
|
||||
.sampler(0, ImageType::FLOAT_1D, "weightTex")
|
||||
.push_constant(Type::BOOL, "useWeight")
|
||||
.vertex_out(overlay_edit_smooth_color_iface)
|
||||
|
@ -512,7 +512,7 @@ GPU_SHADER_CREATE_INFO(overlay_edit_particle_strand_clipped)
|
|||
GPU_SHADER_CREATE_INFO(overlay_edit_particle_point)
|
||||
.do_static_compilation(true)
|
||||
.vertex_in(0, Type::VEC3, "pos")
|
||||
.vertex_in(1, Type::FLOAT, "color")
|
||||
.vertex_in(1, Type::FLOAT, "selection")
|
||||
.vertex_out(overlay_edit_flat_color_iface)
|
||||
.fragment_out(0, Type::VEC4, "fragColor")
|
||||
.vertex_source("overlay_edit_particle_point_vert.glsl")
|
||||
|
@ -630,7 +630,7 @@ GPU_SHADER_CREATE_INFO(overlay_uniform_color_pointcloud)
|
|||
|
||||
GPU_SHADER_CREATE_INFO(overlay_uniform_color_clipped)
|
||||
.do_static_compilation(true)
|
||||
.additional_info("overlay_depth_only", "drw_clipped");
|
||||
.additional_info("overlay_uniform_color", "drw_clipped");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(overlay_uniform_color_pointcloud_clipped)
|
||||
.do_static_compilation(true)
|
||||
|
|
|
@ -19,3 +19,24 @@ GPU_SHADER_CREATE_INFO(overlay_sculpt_curves_selection)
|
|||
GPU_SHADER_CREATE_INFO(overlay_sculpt_curves_selection_clipped)
|
||||
.do_static_compilation(true)
|
||||
.additional_info("overlay_sculpt_curves_selection", "drw_clipped");
|
||||
|
||||
GPU_SHADER_INTERFACE_INFO(overlay_sculpt_curves_cage_iface, "")
|
||||
.no_perspective(Type::VEC2, "edgePos")
|
||||
.flat(Type::VEC2, "edgeStart")
|
||||
.smooth(Type::VEC4, "finalColor");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(overlay_sculpt_curves_cage)
|
||||
.do_static_compilation(true)
|
||||
.vertex_in(0, Type::VEC3, "pos")
|
||||
.vertex_in(1, Type::FLOAT, "selection")
|
||||
.vertex_out(overlay_sculpt_curves_cage_iface)
|
||||
.fragment_out(0, Type::VEC4, "fragColor")
|
||||
.fragment_out(1, Type::VEC4, "lineOutput")
|
||||
.push_constant(Type::FLOAT, "opacity")
|
||||
.vertex_source("overlay_sculpt_curves_cage_vert.glsl")
|
||||
.fragment_source("overlay_extra_frag.glsl")
|
||||
.additional_info("draw_modelmat", "draw_view", "draw_globals");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(overlay_sculpt_curves_cage_clipped)
|
||||
.do_static_compilation(true)
|
||||
.additional_info("overlay_sculpt_curves_cage", "drw_clipped");
|
||||
|
|
|
@ -7,7 +7,7 @@ void main()
|
|||
vec3 world_pos = point_object_to_world(pos);
|
||||
gl_Position = point_world_to_ndc(world_pos);
|
||||
|
||||
finalColor = mix(colorWire, colorVertexSelect, color);
|
||||
finalColor = mix(colorWire, colorVertexSelect, selection);
|
||||
|
||||
gl_PointSize = sizeVertex * 2.0;
|
||||
|
||||
|
|
|
@ -25,10 +25,10 @@ void main()
|
|||
gl_Position = point_world_to_ndc(world_pos);
|
||||
|
||||
if (useWeight) {
|
||||
finalColor = vec4(weight_to_rgb(color), 1.0);
|
||||
finalColor = vec4(weight_to_rgb(selection), 1.0);
|
||||
}
|
||||
else {
|
||||
finalColor = mix(colorWire, colorVertexSelect, color);
|
||||
finalColor = mix(colorWire, colorVertexSelect, selection);
|
||||
}
|
||||
|
||||
view_clipping_distances(world_pos);
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 world_pos = point_object_to_world(pos);
|
||||
gl_Position = point_world_to_ndc(world_pos);
|
||||
|
||||
finalColor = vec4(selection);
|
||||
finalColor.a *= opacity;
|
||||
|
||||
/* Convert to screen position [0..sizeVp]. */
|
||||
edgePos = edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue