WIP: Brush assets project #106303

Draft
Julian Eisel wants to merge 391 commits from brush-assets-project into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
28 changed files with 356 additions and 267 deletions
Showing only changes of commit 30bd6b908f - Show all commits

View File

@ -1399,13 +1399,12 @@ endif()
# Test SIMD support, before platform includes to determine if sse2neon is needed. # Test SIMD support, before platform includes to determine if sse2neon is needed.
if(WITH_CPU_SIMD) if(WITH_CPU_SIMD)
set(COMPILER_SSE_FLAG) set(COMPILER_SSE42_FLAG)
set(COMPILER_SSE2_FLAG)
# Test Neon first since macOS Arm can compile and run x86-64 SSE binaries. # Test Neon first since macOS Arm can compile and run x86-64 SSE binaries.
test_neon_support() test_neon_support()
if(NOT SUPPORT_NEON_BUILD) if(NOT SUPPORT_NEON_BUILD)
test_sse_support(COMPILER_SSE_FLAG COMPILER_SSE2_FLAG) test_sse_support(COMPILER_SSE42_FLAG)
endif() endif()
endif() endif()
@ -1445,8 +1444,6 @@ endif()
# Enable SIMD support if detected by `test_sse_support()` or `test_neon_support()`. # Enable SIMD support if detected by `test_sse_support()` or `test_neon_support()`.
# #
# This is done globally, so that all modules can use it if available, and
# because these are used in headers used by many modules.
if(WITH_CPU_SIMD) if(WITH_CPU_SIMD)
if(SUPPORT_NEON_BUILD) if(SUPPORT_NEON_BUILD)
# Neon # Neon
@ -1456,15 +1453,20 @@ if(WITH_CPU_SIMD)
endif() endif()
else() else()
# SSE # SSE
if(SUPPORT_SSE_BUILD) if(SUPPORT_SSE42_BUILD)
string(PREPEND PLATFORM_CFLAGS "${COMPILER_SSE_FLAG} ") string(APPEND CMAKE_CXX_FLAGS " ${COMPILER_SSE42_FLAG}")
add_definitions(-D__SSE__ -D__MMX__) string(APPEND CMAKE_C_FLAGS " ${COMPILER_SSE42_FLAG}")
endif() # MSVC doesn't define any of these and only does the AVX and higher flags.
if(SUPPORT_SSE2_BUILD) # For consistency we define these flags for MSVC.
string(APPEND PLATFORM_CFLAGS " ${COMPILER_SSE2_FLAG}") if(WIN32)
add_definitions(-D__SSE2__) add_compile_definitions(
if(NOT SUPPORT_SSE_BUILD) # don't double up __MMX__
add_definitions(-D__MMX__) __SSE__
__SSE2__
__SSE3__
__SSE4_1__
__SSE4_2__
)
endif() endif()
endif() endif()
endif() endif()
@ -1479,10 +1481,8 @@ if(FIRST_RUN)
else() else()
message(STATUS "Neon SIMD instructions detected but unused, requires sse2neon") message(STATUS "Neon SIMD instructions detected but unused, requires sse2neon")
endif() endif()
elseif(SUPPORT_SSE2_BUILD) elseif(SUPPORT_SSE42_BUILD)
message(STATUS "SSE2 SIMD instructions enabled") message(STATUS "SSE42 SIMD instructions enabled")
elseif(SUPPORT_SSE_BUILD)
message(STATUS "SSE SIMD instructions enabled")
else() else()
message(STATUS "No SIMD instructions detected") message(STATUS "No SIMD instructions detected")
endif() endif()

View File

@ -540,49 +540,37 @@ function(setup_platform_linker_libs
endfunction() endfunction()
macro(TEST_SSE_SUPPORT macro(TEST_SSE_SUPPORT
_sse_flags _sse42_flags)
_sse2_flags)
include(CheckCSourceRuns) include(CheckCSourceRuns)
# message(STATUS "Detecting SSE support") # message(STATUS "Detecting SSE support")
if(CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang")) if(CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang"))
set(${_sse_flags} "-msse") set(${_sse42_flags} "-march=x86-64-v2")
set(${_sse2_flags} "-msse2")
elseif(MSVC) elseif(MSVC)
# x86_64 has this auto enabled # msvc has no specific build flags for SSE42, but when using intrinsics it will
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") # generate the right instructions.
set(${_sse_flags} "") set(${_sse42_flags} "")
set(${_sse2_flags} "")
else()
set(${_sse_flags} "/arch:SSE")
set(${_sse2_flags} "/arch:SSE2")
endif()
elseif(CMAKE_C_COMPILER_ID STREQUAL "Intel") elseif(CMAKE_C_COMPILER_ID STREQUAL "Intel")
set(${_sse_flags} "") # icc defaults to -msse if(WIN32)
set(${_sse2_flags} "") # icc defaults to -msse2 set(${_sse42_flags} "/QxSSE4.2")
else()
set(${_sse42_flags} "-xsse4.2")
endif()
else() else()
message(WARNING "SSE flags for this compiler: '${CMAKE_C_COMPILER_ID}' not known") message(WARNING "SSE flags for this compiler: '${CMAKE_C_COMPILER_ID}' not known")
set(${_sse_flags}) set(${_sse42_flags})
set(${_sse2_flags})
endif() endif()
set(CMAKE_REQUIRED_FLAGS "${${_sse_flags}} ${${_sse2_flags}}") set(CMAKE_REQUIRED_FLAGS "${${_sse42_flags}}")
if(NOT DEFINED SUPPORT_SSE_BUILD) if(NOT DEFINED SUPPORT_SSE42_BUILD)
# result cached
check_c_source_runs("
#include <xmmintrin.h>
int main(void) { __m128 v = _mm_setzero_ps(); return 0; }"
SUPPORT_SSE_BUILD)
endif()
if(NOT DEFINED SUPPORT_SSE2_BUILD)
# result cached # result cached
check_c_source_runs(" check_c_source_runs("
#include <nmmintrin.h>
#include <emmintrin.h> #include <emmintrin.h>
int main(void) { __m128d v = _mm_setzero_pd(); return 0; }" int main(void) { __m128i v = _mm_setzero_si128(); v = _mm_cmpgt_epi64(v,v); return 0; }"
SUPPORT_SSE2_BUILD) SUPPORT_SSE42_BUILD)
endif() endif()
unset(CMAKE_REQUIRED_FLAGS) unset(CMAKE_REQUIRED_FLAGS)

View File

@ -181,3 +181,7 @@ endif()
if(WITH_FREESTYLE) if(WITH_FREESTYLE)
add_subdirectory(freestyle) add_subdirectory(freestyle)
endif() endif()
if(WITH_CPU_CHECK)
add_subdirectory(cpucheck)
endif()

View File

@ -582,14 +582,6 @@ struct SculptSession {
blender::float3 cursor_sampled_normal; blender::float3 cursor_sampled_normal;
blender::float3 cursor_view_normal; blender::float3 cursor_view_normal;
/* For Sculpt trimming gesture tools, initial ray-cast data from the position of the mouse
* when
* the gesture starts (intersection with the surface and if they ray hit the surface or not).
*/
blender::float3 gesture_initial_location;
blender::float3 gesture_initial_normal;
bool gesture_initial_hit;
/* TODO(jbakker): Replace rv3d and v3d with ViewContext */ /* TODO(jbakker): Replace rv3d and v3d with ViewContext */
RegionView3D *rv3d; RegionView3D *rv3d;
View3D *v3d; View3D *v3d;

View File

@ -98,18 +98,19 @@ void BKE_gpencil_cache_data_init(Depsgraph *depsgraph, Object *ob)
} }
if (mmd->cache_data) { if (mmd->cache_data) {
BKE_shrinkwrap_free_tree(mmd->cache_data); BKE_shrinkwrap_free_tree(mmd->cache_data);
MEM_SAFE_FREE(mmd->cache_data); MEM_delete(mmd->cache_data);
mmd->cache_data = nullptr;
} }
Object *ob_target = DEG_get_evaluated_object(depsgraph, ob); Object *ob_target = DEG_get_evaluated_object(depsgraph, ob);
Mesh *target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target); Mesh *target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target);
mmd->cache_data = static_cast<ShrinkwrapTreeData *>( mmd->cache_data = MEM_new<ShrinkwrapTreeData>(__func__);
MEM_callocN(sizeof(ShrinkwrapTreeData), __func__));
if (BKE_shrinkwrap_init_tree( if (BKE_shrinkwrap_init_tree(
mmd->cache_data, target, mmd->shrink_type, mmd->shrink_mode, false)) mmd->cache_data, target, mmd->shrink_type, mmd->shrink_mode, false))
{ {
} }
else { else {
MEM_SAFE_FREE(mmd->cache_data); MEM_delete(mmd->cache_data);
mmd->cache_data = nullptr;
} }
break; break;
} }
@ -136,7 +137,8 @@ void BKE_gpencil_cache_data_clear(Object *ob)
ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md; ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
if ((mmd) && (mmd->cache_data)) { if ((mmd) && (mmd->cache_data)) {
BKE_shrinkwrap_free_tree(mmd->cache_data); BKE_shrinkwrap_free_tree(mmd->cache_data);
MEM_SAFE_FREE(mmd->cache_data); MEM_delete(mmd->cache_data);
mmd->cache_data = nullptr;
} }
break; break;
} }

View File

@ -321,11 +321,17 @@ void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf,
bool has_bezier_stroke = false; bool has_bezier_stroke = false;
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf.strokes) { LISTBASE_FOREACH (bGPDstroke *, gps, &gpf.strokes) {
if (gps->editcurve != nullptr) { if (gps->editcurve != nullptr) {
if (gps->editcurve->tot_curve_points == 0) {
continue;
}
has_bezier_stroke = true; has_bezier_stroke = true;
num_points += gps->editcurve->tot_curve_points; num_points += gps->editcurve->tot_curve_points;
curve_types.append(CURVE_TYPE_BEZIER); curve_types.append(CURVE_TYPE_BEZIER);
} }
else { else {
if (gps->totpoints == 0) {
continue;
}
num_points += gps->totpoints; num_points += gps->totpoints;
curve_types.append(CURVE_TYPE_POLY); curve_types.append(CURVE_TYPE_POLY);
} }
@ -333,13 +339,17 @@ void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf,
offsets.append(num_points); offsets.append(num_points);
} }
/* Return if the legacy frame contains no strokes (or zero points). */
if (num_strokes == 0) {
return;
}
/* Resize the CurvesGeometry. */ /* Resize the CurvesGeometry. */
Drawing &drawing = r_drawing.wrap(); Drawing &drawing = r_drawing.wrap();
CurvesGeometry &curves = drawing.strokes_for_write(); CurvesGeometry &curves = drawing.strokes_for_write();
curves.resize(num_points, num_strokes); curves.resize(num_points, num_strokes);
if (num_strokes > 0) { curves.offsets_for_write().copy_from(offsets);
curves.offsets_for_write().copy_from(offsets);
}
OffsetIndices<int> points_by_curve = curves.points_by_curve(); OffsetIndices<int> points_by_curve = curves.points_by_curve();
MutableAttributeAccessor attributes = curves.attributes_for_write(); MutableAttributeAccessor attributes = curves.attributes_for_write();
@ -416,7 +426,16 @@ void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf,
Array<float4x2> legacy_texture_matrices(num_strokes); Array<float4x2> legacy_texture_matrices(num_strokes);
int stroke_i = 0; int stroke_i = 0;
LISTBASE_FOREACH_INDEX (bGPDstroke *, gps, &gpf.strokes, stroke_i) { LISTBASE_FOREACH (bGPDstroke *, gps, &gpf.strokes) {
/* In GPv2 strokes with 0 points could technically be represented. In `CurvesGeometry` this is
* not the case and would be a bug. So we explicitly make sure to skip over strokes with no
* points. */
if (gps->totpoints == 0 ||
(gps->editcurve != nullptr && gps->editcurve->tot_curve_points == 0))
{
continue;
}
stroke_cyclic.span[stroke_i] = (gps->flag & GP_STROKE_CYCLIC) != 0; stroke_cyclic.span[stroke_i] = (gps->flag & GP_STROKE_CYCLIC) != 0;
/* TODO: This should be a `double` attribute. */ /* TODO: This should be a `double` attribute. */
stroke_init_times.span[stroke_i] = float(gps->inittime); stroke_init_times.span[stroke_i] = float(gps->inittime);
@ -428,10 +447,8 @@ void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf,
stroke_fill_colors[stroke_i] = ColorGeometry4f(gps->vert_color_fill); stroke_fill_colors[stroke_i] = ColorGeometry4f(gps->vert_color_fill);
stroke_materials.span[stroke_i] = gps->mat_nr; stroke_materials.span[stroke_i] = gps->mat_nr;
IndexRange points = points_by_curve[stroke_i]; const IndexRange points = points_by_curve[stroke_i];
if (points.is_empty()) { BLI_assert(points.size() == gps->totpoints);
continue;
}
const Span<bGPDspoint> src_points{gps->points, gps->totpoints}; const Span<bGPDspoint> src_points{gps->points, gps->totpoints};
/* Previously, Grease Pencil used a radius convention where 1 `px` = 0.001 units. This `px` /* Previously, Grease Pencil used a radius convention where 1 `px` = 0.001 units. This `px`
@ -512,6 +529,8 @@ void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf,
const float4x2 legacy_texture_matrix = get_legacy_texture_matrix(gps); const float4x2 legacy_texture_matrix = get_legacy_texture_matrix(gps);
legacy_texture_matrices[stroke_i] = legacy_texture_matrix; legacy_texture_matrices[stroke_i] = legacy_texture_matrix;
stroke_i++;
} }
/* Ensure that the normals are up to date. */ /* Ensure that the normals are up to date. */

View File

@ -0,0 +1,26 @@
# SPDX-FileCopyrightText: 2024 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
# The cpu check module cannot build with sse42 since it will be executed
# by cpus that may not support these instructions
if(COMPILER_SSE42_FLAG)
remove_cc_flag("${COMPILER_SSE42_FLAG}")
endif()
add_library(blender_cpu_check SHARED cpu_check.cc)
target_link_libraries(blender_cpu_check PRIVATE ${PLATFORM_LINKLIBS})
target_compile_definitions(blender_cpu_check PUBLIC WITH_CPU_CHECK)
if(NOT WIN32)
set(_LIB_SUB_FOLDER "lib/")
endif()
set_target_properties(blender_cpu_check
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/${_LIB_SUB_FOLDER}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/${_LIB_SUB_FOLDER}"
)
unset(_LIB_SUB_FOLDER)

View File

@ -276,12 +276,6 @@ static void compositor_engine_draw(void *data)
* the GPU for extended periods of time and sub-optimally schedule work for execution. */ * the GPU for extended periods of time and sub-optimally schedule work for execution. */
GPU_flush(); GPU_flush();
} }
else {
/* Realtime Compositor is not supported on macOS with the OpenGL backend. */
blender::StringRef("Viewport compositor is only supported on MacOS with the Metal Backend.")
.copy(compositor_data->info, GPU_INFO_SIZE);
return;
}
#endif #endif
/* Execute Compositor render commands. */ /* Execute Compositor render commands. */

View File

@ -3259,14 +3259,6 @@ void DRW_gpu_context_enable_ex(bool /*restore*/)
void DRW_gpu_context_disable_ex(bool restore) void DRW_gpu_context_disable_ex(bool restore)
{ {
if (DST.system_gpu_context != nullptr) { if (DST.system_gpu_context != nullptr) {
#ifdef __APPLE__
/* Need to flush before disabling draw context, otherwise it does not
* always finish drawing and viewport can be empty or partially drawn */
if (GPU_type_matches_ex(GPU_DEVICE_ANY, GPU_OS_MAC, GPU_DRIVER_ANY, GPU_BACKEND_OPENGL)) {
GPU_flush();
}
#endif
if (BLI_thread_is_main() && restore) { if (BLI_thread_is_main() && restore) {
wm_window_reset_drawable(); wm_window_reset_drawable();
} }

View File

@ -315,7 +315,7 @@ void AssetClearHelper::reportResults(const bContext *C, ReportList &reports) con
&reports, RPT_INFO, "Data-block '%s' is not an asset anymore", stats.last_id->name + 2); &reports, RPT_INFO, "Data-block '%s' is not an asset anymore", stats.last_id->name + 2);
} }
else { else {
BKE_reportf(&reports, RPT_INFO, "%i data-blocks are no assets anymore", stats.tot_cleared); BKE_reportf(&reports, RPT_INFO, "%i data-blocks are not assets anymore", stats.tot_cleared);
} }
} }

View File

@ -1105,20 +1105,6 @@ void UI_widgetbase_draw_cache_end()
GPU_blend(GPU_BLEND_NONE); GPU_blend(GPU_BLEND_NONE);
} }
/* Disable cached/instanced drawing and enforce single widget drawing pipeline.
* Works around interface artifacts happening on certain driver and hardware
* configurations. */
static bool draw_widgetbase_batch_skip_draw_cache()
{
/* MacOS is known to have issues on Mac Mini and MacBook Pro with Intel Iris GPU.
* For example, #78307. */
if (GPU_type_matches_ex(GPU_DEVICE_INTEL, GPU_OS_MAC, GPU_DRIVER_ANY, GPU_BACKEND_OPENGL)) {
return true;
}
return false;
}
static void draw_widgetbase_batch(uiWidgetBase *wtb) static void draw_widgetbase_batch(uiWidgetBase *wtb)
{ {
wtb->uniform_params.tria_type = wtb->tria1.type; wtb->uniform_params.tria_type = wtb->tria1.type;
@ -1127,7 +1113,7 @@ static void draw_widgetbase_batch(uiWidgetBase *wtb)
copy_v2_v2(wtb->uniform_params.tria1_center, wtb->tria1.center); copy_v2_v2(wtb->uniform_params.tria1_center, wtb->tria1.center);
copy_v2_v2(wtb->uniform_params.tria2_center, wtb->tria2.center); copy_v2_v2(wtb->uniform_params.tria2_center, wtb->tria2.center);
if (g_widget_base_batch.enabled && !draw_widgetbase_batch_skip_draw_cache()) { if (g_widget_base_batch.enabled) {
g_widget_base_batch.params[g_widget_base_batch.count] = wtb->uniform_params; g_widget_base_batch.params[g_widget_base_batch.count] = wtb->uniform_params;
g_widget_base_batch.count++; g_widget_base_batch.count++;

View File

@ -284,16 +284,6 @@ void immDrawPixelsTexTiled_scaling_clipping(IMMDrawPixelsTexState *state,
immAttr2f(texco, left / float(tex_w), top / float(tex_h)); immAttr2f(texco, left / float(tex_w), top / float(tex_h));
immVertex2f(pos, rast_x + offset_left * xzoom, rast_y + top * yzoom * scaleY); immVertex2f(pos, rast_x + offset_left * xzoom, rast_y + top * yzoom * scaleY);
immEnd(); immEnd();
/* NOTE: Weirdly enough this is only required on macOS. Without this there is some sort of
* bleeding of data is happening from tiles which are drawn later on.
* This doesn't seem to be too slow,
* but still would be nice to have fast and nice solution. */
#ifdef __APPLE__
if (GPU_type_matches_ex(GPU_DEVICE_ANY, GPU_OS_MAC, GPU_DRIVER_ANY, GPU_BACKEND_OPENGL)) {
GPU_flush();
}
#endif
} }
} }

View File

@ -38,6 +38,7 @@
#include "sculpt_intern.hh" #include "sculpt_intern.hh"
namespace blender::ed::sculpt_paint::trim { namespace blender::ed::sculpt_paint::trim {
enum class OperationType { enum class OperationType {
Intersect = 0, Intersect = 0,
Difference = 1, Difference = 1,
@ -105,20 +106,24 @@ static EnumPropertyItem solver_modes[] = {
struct TrimOperation { struct TrimOperation {
gesture::Operation op; gesture::Operation op;
/* Operation-generated geometry. */
Mesh *mesh; Mesh *mesh;
float (*true_mesh_co)[3]; float (*true_mesh_co)[3];
float depth_front; /* Operator properties. */
float depth_back;
bool use_cursor_depth; bool use_cursor_depth;
bool initial_hit;
blender::float3 initial_location;
blender::float3 initial_normal;
OperationType mode; OperationType mode;
SolverMode solver_mode; SolverMode solver_mode;
OrientationType orientation; OrientationType orientation;
ExtrudeMode extrude_mode; ExtrudeMode extrude_mode;
}; };
/* Recalculate the mesh normals for the generated trim mesh. */
static void update_normals(gesture::GestureData &gesture_data) static void update_normals(gesture::GestureData &gesture_data)
{ {
TrimOperation *trim_operation = (TrimOperation *)gesture_data.operation; TrimOperation *trim_operation = (TrimOperation *)gesture_data.operation;
@ -151,8 +156,8 @@ static void update_normals(gesture::GestureData &gesture_data)
trim_operation->mesh = result; trim_operation->mesh = result;
} }
/* Get the origin and normal that are going to be used for calculating the depth and position the /* Get the origin and normal that are going to be used for calculating the depth and position of
* trimming geometry. */ * the trimming geometry. */
static void get_origin_and_normal(gesture::GestureData &gesture_data, static void get_origin_and_normal(gesture::GestureData &gesture_data,
float *r_origin, float *r_origin,
float *r_normal) float *r_normal)
@ -166,23 +171,26 @@ static void get_origin_and_normal(gesture::GestureData &gesture_data,
case OrientationType::View: case OrientationType::View:
mul_v3_m4v3(r_origin, mul_v3_m4v3(r_origin,
gesture_data.vc.obact->object_to_world().ptr(), gesture_data.vc.obact->object_to_world().ptr(),
gesture_data.ss->gesture_initial_location); trim_operation->initial_location);
copy_v3_v3(r_normal, gesture_data.world_space_view_normal); copy_v3_v3(r_normal, gesture_data.world_space_view_normal);
negate_v3(r_normal); negate_v3(r_normal);
break; break;
case OrientationType::Surface: case OrientationType::Surface:
mul_v3_m4v3(r_origin, mul_v3_m4v3(r_origin,
gesture_data.vc.obact->object_to_world().ptr(), gesture_data.vc.obact->object_to_world().ptr(),
gesture_data.ss->gesture_initial_location); trim_operation->initial_location);
/* Transforming the normal does not take non uniform scaling into account. Sculpt mode is not /* Transforming the normal does not take non uniform scaling into account. Sculpt mode is not
* expected to work on object with non uniform scaling. */ * expected to work on object with non uniform scaling. */
copy_v3_v3(r_normal, gesture_data.ss->gesture_initial_normal); copy_v3_v3(r_normal, trim_operation->initial_normal);
mul_mat3_m4_v3(gesture_data.vc.obact->object_to_world().ptr(), r_normal); mul_mat3_m4_v3(gesture_data.vc.obact->object_to_world().ptr(), r_normal);
break; break;
} }
} }
static void calculate_depth(gesture::GestureData &gesture_data) /* Calculates the depth of the drawn shape inside the scene.*/
static void calculate_depth(gesture::GestureData &gesture_data,
float &r_depth_front,
float &r_depth_back)
{ {
TrimOperation *trim_operation = (TrimOperation *)gesture_data.operation; TrimOperation *trim_operation = (TrimOperation *)gesture_data.operation;
@ -197,8 +205,8 @@ static void calculate_depth(gesture::GestureData &gesture_data)
get_origin_and_normal(gesture_data, shape_origin, shape_normal); get_origin_and_normal(gesture_data, shape_origin, shape_normal);
plane_from_point_normal_v3(shape_plane, shape_origin, shape_normal); plane_from_point_normal_v3(shape_plane, shape_origin, shape_normal);
trim_operation->depth_front = FLT_MAX; float depth_front = FLT_MAX;
trim_operation->depth_back = -FLT_MAX; float depth_back = -FLT_MAX;
for (int i = 0; i < totvert; i++) { for (int i = 0; i < totvert; i++) {
PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
@ -210,35 +218,33 @@ static void calculate_depth(gesture::GestureData &gesture_data)
float world_space_vco[3]; float world_space_vco[3];
mul_v3_m4v3(world_space_vco, vc->obact->object_to_world().ptr(), vco); mul_v3_m4v3(world_space_vco, vc->obact->object_to_world().ptr(), vco);
const float dist = dist_signed_to_plane_v3(world_space_vco, shape_plane); const float dist = dist_signed_to_plane_v3(world_space_vco, shape_plane);
trim_operation->depth_front = min_ff(dist, trim_operation->depth_front); depth_front = min_ff(dist, depth_front);
trim_operation->depth_back = max_ff(dist, trim_operation->depth_back); depth_back = max_ff(dist, depth_back);
} }
if (trim_operation->use_cursor_depth) { if (trim_operation->use_cursor_depth) {
float world_space_gesture_initial_location[3]; float world_space_gesture_initial_location[3];
mul_v3_m4v3(world_space_gesture_initial_location, mul_v3_m4v3(world_space_gesture_initial_location,
vc->obact->object_to_world().ptr(), vc->obact->object_to_world().ptr(),
ss->gesture_initial_location); trim_operation->initial_location);
float mid_point_depth; float mid_point_depth;
if (trim_operation->orientation == OrientationType::View) { if (trim_operation->orientation == OrientationType::View) {
mid_point_depth = ss->gesture_initial_hit ? mid_point_depth = trim_operation->initial_hit ?
dist_signed_to_plane_v3(world_space_gesture_initial_location, dist_signed_to_plane_v3(world_space_gesture_initial_location,
shape_plane) : shape_plane) :
(trim_operation->depth_back + trim_operation->depth_front) * 0.5f; (depth_back + depth_front) * 0.5f;
} }
else { else {
/* When using normal orientation, if the stroke started over the mesh, position the mid point /* When using normal orientation, if the stroke started over the mesh, position the mid point
* at 0 distance from the shape plane. This positions the trimming shape half inside of the * at 0 distance from the shape plane. This positions the trimming shape half inside of the
* surface. */ * surface. */
mid_point_depth = ss->gesture_initial_hit ? mid_point_depth = trim_operation->initial_hit ? 0.0f : (depth_back + depth_front) * 0.5f;
0.0f :
(trim_operation->depth_back + trim_operation->depth_front) * 0.5f;
} }
float depth_radius; float depth_radius;
if (ss->gesture_initial_hit) { if (trim_operation->initial_hit) {
depth_radius = ss->cursor_radius; depth_radius = ss->cursor_radius;
} }
else { else {
@ -253,16 +259,19 @@ static void calculate_depth(gesture::GestureData &gesture_data)
if (!BKE_brush_use_locked_size(scene, brush)) { if (!BKE_brush_use_locked_size(scene, brush)) {
depth_radius = paint_calc_object_space_radius( depth_radius = paint_calc_object_space_radius(
vc, ss->gesture_initial_location, BKE_brush_size_get(scene, brush)); vc, trim_operation->initial_location, BKE_brush_size_get(scene, brush));
} }
else { else {
depth_radius = BKE_brush_unprojected_radius_get(scene, brush); depth_radius = BKE_brush_unprojected_radius_get(scene, brush);
} }
} }
trim_operation->depth_front = mid_point_depth - depth_radius; depth_front = mid_point_depth - depth_radius;
trim_operation->depth_back = mid_point_depth + depth_radius; depth_back = mid_point_depth + depth_radius;
} }
r_depth_front = depth_front;
r_depth_back = depth_back;
} }
static void generate_geometry(gesture::GestureData &gesture_data) static void generate_geometry(gesture::GestureData &gesture_data)
@ -281,20 +290,6 @@ static void generate_geometry(gesture::GestureData &gesture_data)
trim_operation->true_mesh_co = static_cast<float(*)[3]>( trim_operation->true_mesh_co = static_cast<float(*)[3]>(
MEM_malloc_arrayN(trim_totverts, sizeof(float[3]), "mesh orco")); MEM_malloc_arrayN(trim_totverts, sizeof(float[3]), "mesh orco"));
float depth_front = trim_operation->depth_front;
float depth_back = trim_operation->depth_back;
float pad_factor = 0.0f;
if (!trim_operation->use_cursor_depth) {
pad_factor = (depth_back - depth_front) * 0.01f + 0.001f;
/* When using cursor depth, don't modify the depth set by the cursor radius. If full depth is
* used, adding a little padding to the trimming shape can help avoiding booleans with coplanar
* faces. */
depth_front -= pad_factor;
depth_back += pad_factor;
}
float shape_origin[3]; float shape_origin[3];
float shape_normal[3]; float shape_normal[3];
float shape_plane[4]; float shape_plane[4];
@ -306,6 +301,20 @@ static void generate_geometry(gesture::GestureData &gesture_data)
/* Write vertices coordinates OperationType::Difference for the front face. */ /* Write vertices coordinates OperationType::Difference for the front face. */
MutableSpan<float3> positions = trim_operation->mesh->vert_positions_for_write(); MutableSpan<float3> positions = trim_operation->mesh->vert_positions_for_write();
float depth_front;
float depth_back;
calculate_depth(gesture_data, depth_front, depth_back);
if (!trim_operation->use_cursor_depth) {
float pad_factor = (depth_back - depth_front) * 0.01f + 0.001f;
/* When using cursor depth, don't modify the depth set by the cursor radius. If full depth is
* used, adding a little padding to the trimming shape can help avoiding booleans with coplanar
* faces. */
depth_front -= pad_factor;
depth_back += pad_factor;
}
float depth_point[3]; float depth_point[3];
/* Get origin point for OrientationType::View. /* Get origin point for OrientationType::View.
@ -436,11 +445,16 @@ static void generate_geometry(gesture::GestureData &gesture_data)
update_normals(gesture_data); update_normals(gesture_data);
} }
static void free_geometry(gesture::GestureData &gesture_data) static void gesture_begin(bContext &C, gesture::GestureData &gesture_data)
{ {
TrimOperation *trim_operation = (TrimOperation *)gesture_data.operation; Object *object = gesture_data.vc.obact;
BKE_id_free(nullptr, trim_operation->mesh); SculptSession *ss = object->sculpt;
MEM_freeN(trim_operation->true_mesh_co);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(&C);
generate_geometry(gesture_data);
SCULPT_topology_islands_invalidate(ss);
BKE_sculpt_update_object_for_edit(depsgraph, gesture_data.vc.obact, false);
undo::push_node(gesture_data.vc.obact, nullptr, undo::Type::Geometry);
} }
static int bm_face_isect_pair(BMFace *f, void * /*user_data*/) static int bm_face_isect_pair(BMFace *f, void * /*user_data*/)
@ -545,19 +559,6 @@ static void apply_trim(gesture::GestureData &gesture_data)
result, static_cast<Mesh *>(gesture_data.vc.obact->data), gesture_data.vc.obact); result, static_cast<Mesh *>(gesture_data.vc.obact->data), gesture_data.vc.obact);
} }
static void gesture_begin(bContext &C, gesture::GestureData &gesture_data)
{
Object *object = gesture_data.vc.obact;
SculptSession *ss = object->sculpt;
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(&C);
calculate_depth(gesture_data);
generate_geometry(gesture_data);
SCULPT_topology_islands_invalidate(ss);
BKE_sculpt_update_object_for_edit(depsgraph, gesture_data.vc.obact, false);
undo::push_node(gesture_data.vc.obact, nullptr, undo::Type::Geometry);
}
static void gesture_apply_for_symmetry_pass(bContext & /*C*/, gesture::GestureData &gesture_data) static void gesture_apply_for_symmetry_pass(bContext & /*C*/, gesture::GestureData &gesture_data)
{ {
TrimOperation *trim_operation = (TrimOperation *)gesture_data.operation; TrimOperation *trim_operation = (TrimOperation *)gesture_data.operation;
@ -570,6 +571,13 @@ static void gesture_apply_for_symmetry_pass(bContext & /*C*/, gesture::GestureDa
apply_trim(gesture_data); apply_trim(gesture_data);
} }
static void free_geometry(gesture::GestureData &gesture_data)
{
TrimOperation *trim_operation = (TrimOperation *)gesture_data.operation;
BKE_id_free(nullptr, trim_operation->mesh);
MEM_freeN(trim_operation->true_mesh_co);
}
static void gesture_end(bContext & /*C*/, gesture::GestureData &gesture_data) static void gesture_end(bContext & /*C*/, gesture::GestureData &gesture_data)
{ {
Object *object = gesture_data.vc.obact; Object *object = gesture_data.vc.obact;
@ -606,13 +614,27 @@ static void init_operation(gesture::GestureData &gesture_data, wmOperator &op)
trim_operation->solver_mode = SolverMode(RNA_enum_get(op.ptr, "trim_solver")); trim_operation->solver_mode = SolverMode(RNA_enum_get(op.ptr, "trim_solver"));
/* If the cursor was not over the mesh, force the orientation to view. */ /* If the cursor was not over the mesh, force the orientation to view. */
if (!gesture_data.ss->gesture_initial_hit) { if (!trim_operation->initial_hit) {
trim_operation->orientation = OrientationType::View; trim_operation->orientation = OrientationType::View;
} }
} }
static void operator_properties(wmOperatorType *ot) static void operator_properties(wmOperatorType *ot)
{ {
PropertyRNA *prop;
prop = RNA_def_int_vector(ot->srna,
"location",
2,
nullptr,
INT_MIN,
INT_MAX,
"Location",
"Mouse location",
INT_MIN,
INT_MAX);
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
RNA_def_enum(ot->srna, RNA_def_enum(ot->srna,
"trim_mode", "trim_mode",
operation_types, operation_types,
@ -669,21 +691,26 @@ static bool can_exec(const bContext &C)
return true; return true;
} }
static void initialize_cursor_info(bContext &C, const wmEvent *event) static void initialize_cursor_info(bContext &C,
const wmOperator &op,
gesture::GestureData &gesture_data)
{ {
const Object &ob = *CTX_data_active_object(&C); const Object &ob = *CTX_data_active_object(&C);
SculptSession &ss = *ob.sculpt; SculptSession &ss = *ob.sculpt;
SCULPT_vertex_random_access_ensure(&ss); SCULPT_vertex_random_access_ensure(&ss);
SculptCursorGeometryInfo sgi; int mval[2];
const float mval_fl[2] = {float(event->mval[0]), float(event->mval[1])}; RNA_int_get_array(op.ptr, "location", mval);
/* TODO: Remove gesture_* properties from SculptSession */ SculptCursorGeometryInfo sgi;
ss.gesture_initial_hit = SCULPT_cursor_geometry_info_update(&C, &sgi, mval_fl, false); const float mval_fl[2] = {float(mval[0]), float(mval[1])};
if (ss.gesture_initial_hit) {
copy_v3_v3(ss.gesture_initial_location, sgi.location); TrimOperation *trim_operation = (TrimOperation *)gesture_data.operation;
copy_v3_v3(ss.gesture_initial_normal, sgi.normal); trim_operation->initial_hit = SCULPT_cursor_geometry_info_update(&C, &sgi, mval_fl, false);
if (trim_operation->initial_hit) {
copy_v3_v3(trim_operation->initial_location, sgi.location);
copy_v3_v3(trim_operation->initial_normal, sgi.normal);
} }
} }
@ -698,7 +725,9 @@ static int gesture_box_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;
} }
initialize_cursor_info(*C, *op, *gesture_data);
init_operation(*gesture_data, *op); init_operation(*gesture_data, *op);
gesture::apply(*C, *gesture_data, *op); gesture::apply(*C, *gesture_data, *op);
return OPERATOR_FINISHED; return OPERATOR_FINISHED;
} }
@ -709,7 +738,7 @@ static int gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;
} }
initialize_cursor_info(*C, event); RNA_int_set_array(op->ptr, "location", event->mval);
return WM_gesture_box_invoke(C, op, event); return WM_gesture_box_invoke(C, op, event);
} }
@ -724,7 +753,10 @@ static int gesture_lasso_exec(bContext *C, wmOperator *op)
if (!gesture_data) { if (!gesture_data) {
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;
} }
initialize_cursor_info(*C, *op, *gesture_data);
init_operation(*gesture_data, *op); init_operation(*gesture_data, *op);
gesture::apply(*C, *gesture_data, *op); gesture::apply(*C, *gesture_data, *op);
return OPERATOR_FINISHED; return OPERATOR_FINISHED;
} }
@ -735,7 +767,7 @@ static int gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *even
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;
} }
initialize_cursor_info(*C, event); RNA_int_set_array(op->ptr, "location", event->mval);
return WM_gesture_lasso_invoke(C, op, event); return WM_gesture_lasso_invoke(C, op, event);
} }

View File

@ -1332,7 +1332,8 @@ static void create_inspection_string_for_generic_value(const bNodeSocket &socket
((*static_cast<bool *>(socket_value)) ? TIP_("True") : TIP_("False"))); ((*static_cast<bool *>(socket_value)) ? TIP_("True") : TIP_("False")));
} }
else if (socket_type.is<float4x4>()) { else if (socket_type.is<float4x4>()) {
const float4x4 &value = *static_cast<const float4x4 *>(socket_value); /* Transpose to be able to print row by row. */
const float4x4 value = math::transpose(*static_cast<const float4x4 *>(socket_value));
ss << value[0] << ",\n"; ss << value[0] << ",\n";
ss << value[1] << ",\n"; ss << value[1] << ",\n";
ss << value[2] << ",\n"; ss << value[2] << ",\n";
@ -1480,8 +1481,7 @@ static void create_inspection_string_for_geometry_info(const geo_log::GeometryIn
} }
static void create_inspection_string_for_geometry_socket(std::stringstream &ss, static void create_inspection_string_for_geometry_socket(std::stringstream &ss,
const nodes::decl::Geometry *socket_decl, const nodes::decl::Geometry *socket_decl)
const bool after_log)
{ {
/* If the geometry declaration is null, as is the case for input to group output, /* If the geometry declaration is null, as is the case for input to group output,
* or it is an output socket don't show supported types. */ * or it is an output socket don't show supported types. */
@ -1489,10 +1489,6 @@ static void create_inspection_string_for_geometry_socket(std::stringstream &ss,
return; return;
} }
if (after_log) {
ss << ".\n\n";
}
Span<bke::GeometryComponent::Type> supported_types = socket_decl->supported_types(); Span<bke::GeometryComponent::Type> supported_types = socket_decl->supported_types();
if (supported_types.is_empty()) { if (supported_types.is_empty()) {
ss << TIP_("Supported: All Types"); ss << TIP_("Supported: All Types");
@ -1536,17 +1532,34 @@ static void create_inspection_string_for_geometry_socket(std::stringstream &ss,
} }
} }
static std::optional<std::string> create_socket_inspection_string( static std::optional<std::string> create_description_inspection_string(const bNodeSocket &socket)
geo_log::GeoTreeLog &geo_tree_log, const bNodeSocket &socket) {
if (socket.runtime->declaration == nullptr) {
return std::nullopt;
}
const blender::nodes::SocketDeclaration &socket_decl = *socket.runtime->declaration;
blender::StringRefNull description = socket_decl.description;
if (description.is_empty()) {
return std::nullopt;
}
return TIP_(description.c_str());
}
static std::optional<std::string> create_log_inspection_string(geo_log::GeoTreeLog *geo_tree_log,
const bNodeSocket &socket)
{ {
using namespace blender::nodes::geo_eval_log; using namespace blender::nodes::geo_eval_log;
if (geo_tree_log == nullptr) {
return std::nullopt;
}
if (socket.typeinfo->base_cpp_type == nullptr) { if (socket.typeinfo->base_cpp_type == nullptr) {
return std::nullopt; return std::nullopt;
} }
geo_tree_log.ensure_socket_values(); geo_tree_log->ensure_socket_values();
ValueLog *value_log = geo_tree_log.find_socket_value_log(socket); ValueLog *value_log = geo_tree_log->find_socket_value_log(socket);
std::stringstream ss; std::stringstream ss;
if (const geo_log::GenericValueLog *generic_value_log = if (const geo_log::GenericValueLog *generic_value_log =
dynamic_cast<const geo_log::GenericValueLog *>(value_log)) dynamic_cast<const geo_log::GenericValueLog *>(value_log))
@ -1564,11 +1577,20 @@ static std::optional<std::string> create_socket_inspection_string(
create_inspection_string_for_geometry_info(*geo_value_log, ss); create_inspection_string_for_geometry_info(*geo_value_log, ss);
} }
std::string str = ss.str();
if (str.empty()) {
return std::nullopt;
}
return str;
}
static std::optional<std::string> create_declaration_inspection_string(const bNodeSocket &socket)
{
std::stringstream ss;
if (const nodes::decl::Geometry *socket_decl = dynamic_cast<const nodes::decl::Geometry *>( if (const nodes::decl::Geometry *socket_decl = dynamic_cast<const nodes::decl::Geometry *>(
socket.runtime->declaration)) socket.runtime->declaration))
{ {
const bool after_log = value_log != nullptr; create_inspection_string_for_geometry_socket(ss, socket_decl);
create_inspection_string_for_geometry_socket(ss, socket_decl, after_log);
} }
std::string str = ss.str(); std::string str = ss.str();
@ -1590,15 +1612,6 @@ static std::string node_socket_get_tooltip(const SpaceNode *snode,
} }
} }
std::stringstream output;
if (socket.runtime->declaration != nullptr) {
const blender::nodes::SocketDeclaration &socket_decl = *socket.runtime->declaration;
blender::StringRefNull description = socket_decl.description;
if (!description.is_empty()) {
output << TIP_(description.c_str());
}
}
geo_log::GeoTreeLog *geo_tree_log = [&]() -> geo_log::GeoTreeLog * { geo_log::GeoTreeLog *geo_tree_log = [&]() -> geo_log::GeoTreeLog * {
const bNodeTreeZones *zones = ntree.zones(); const bNodeTreeZones *zones = ntree.zones();
if (!zones) { if (!zones) {
@ -1608,27 +1621,45 @@ static std::string node_socket_get_tooltip(const SpaceNode *snode,
return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr); return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr);
}(); }();
if (ntree.type == NTREE_GEOMETRY && geo_tree_log != nullptr) { Vector<std::string> inspection_strings;
if (!output.str().empty()) {
if (std::optional<std::string> info = create_description_inspection_string(socket)) {
inspection_strings.append(std::move(*info));
}
if (std::optional<std::string> info = create_log_inspection_string(geo_tree_log, socket)) {
inspection_strings.append(std::move(*info));
}
if (std::optional<std::string> info = create_declaration_inspection_string(socket)) {
inspection_strings.append(std::move(*info));
}
std::stringstream output;
for (const std::string &info : inspection_strings) {
output << info;
if (&info != &inspection_strings.last()) {
output << ".\n\n"; output << ".\n\n";
} }
}
std::optional<std::string> socket_inspection_str = create_socket_inspection_string( if (inspection_strings.is_empty()) {
*geo_tree_log, socket); const bNode &node = socket.owner_node();
if (socket_inspection_str.has_value()) { if (node.is_reroute()) {
output << *socket_inspection_str; char reroute_name[MAX_NAME];
bke::nodeLabel(&ntree, &node, reroute_name, sizeof(reroute_name));
output << reroute_name;
} }
else { else {
output << bke::nodeSocketLabel(&socket);
}
if (ntree.type == NTREE_GEOMETRY) {
output << ".\n\n";
output << TIP_( output << TIP_(
"Unknown socket value. Either the socket was not used or its value was not logged " "Unknown socket value. Either the socket was not used or its value was not logged "
"during the last evaluation"); "during the last evaluation");
} }
} }
if (output.str().empty()) {
output << bke::nodeSocketLabel(&socket);
}
return output.str(); return output.str();
} }

View File

@ -7,6 +7,7 @@
#include <fmt/format.h> #include <fmt/format.h>
#include "BLI_math_matrix.hh"
#include "BLI_math_quaternion_types.hh" #include "BLI_math_quaternion_types.hh"
#include "BLI_math_vector_types.hh" #include "BLI_math_vector_types.hh"
@ -395,7 +396,8 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
UI_but_func_tooltip_set( UI_but_func_tooltip_set(
but, but,
[](bContext * /*C*/, void *argN, const char * /*tip*/) { [](bContext * /*C*/, void *argN, const char * /*tip*/) {
const float4x4 &value = *static_cast<const float4x4 *>(argN); /* Transpose to be able to print row by row. */
const float4x4 value = math::transpose(*static_cast<const float4x4 *>(argN));
std::stringstream ss; std::stringstream ss;
ss << value[0] << ",\n"; ss << value[0] << ",\n";
ss << value[1] << ",\n"; ss << value[1] << ",\n";

View File

@ -238,6 +238,10 @@ ReverseUVSampler::Result ReverseUVSampler::sample(const float2 &query_uv) const
* the lookup can fail for floating point accuracy reasons when the uv is almost exact on an * the lookup can fail for floating point accuracy reasons when the uv is almost exact on an
* edge. */ * edge. */
const float edge_epsilon = 0.00001f; const float edge_epsilon = 0.00001f;
/* If uv triangles are very small, it may look like the query hits multiple triangles due to
* floating point precision issues. Better just pick one of the triangles instead of failing the
* entire operation in this case. */
const float area_epsilon = 0.00001f;
for (const int tri_i : tri_indices) { for (const int tri_i : tri_indices) {
const int3 &tri = corner_tris_[tri_i]; const int3 &tri = corner_tris_[tri_i];
@ -260,8 +264,14 @@ ReverseUVSampler::Result ReverseUVSampler::sample(const float2 &query_uv) const
const float worse_dist = std::max(dist, best_dist); const float worse_dist = std::max(dist, best_dist);
/* Allow ignoring multiple triangle intersections if the uv is almost exactly on an edge. */ /* Allow ignoring multiple triangle intersections if the uv is almost exactly on an edge. */
if (worse_dist < -edge_epsilon) { if (worse_dist < -edge_epsilon) {
/* The uv sample is in multiple triangles. */ const int3 &best_tri = corner_tris_[tri_i];
return Result{ResultType::Multiple}; const float best_tri_area = area_tri_v2(
uv_map_[best_tri[0]], uv_map_[best_tri[1]], uv_map_[best_tri[2]]);
const float current_tri_area = area_tri_v2(uv_0, uv_1, uv_2);
if (best_tri_area > area_epsilon && current_tri_area > area_epsilon) {
/* The uv sample is in multiple triangles. */
return Result{ResultType::Multiple};
}
} }
} }

View File

@ -139,12 +139,12 @@ static void bake_modifier(Main * /*bmain*/,
/* Recalculate shrinkwrap data. */ /* Recalculate shrinkwrap data. */
if (mmd->cache_data) { if (mmd->cache_data) {
BKE_shrinkwrap_free_tree(mmd->cache_data); BKE_shrinkwrap_free_tree(mmd->cache_data);
MEM_SAFE_FREE(mmd->cache_data); MEM_delete(mmd->cache_data);
mmd->cache_data = nullptr;
} }
Object *ob_target = DEG_get_evaluated_object(depsgraph, mmd->target); Object *ob_target = DEG_get_evaluated_object(depsgraph, mmd->target);
Mesh *target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target); Mesh *target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target);
mmd->cache_data = static_cast<ShrinkwrapTreeData *>( mmd->cache_data = MEM_new<ShrinkwrapTreeData>(__func__);
MEM_callocN(sizeof(ShrinkwrapTreeData), __func__));
if (BKE_shrinkwrap_init_tree( if (BKE_shrinkwrap_init_tree(
mmd->cache_data, target, mmd->shrink_type, mmd->shrink_mode, false)) mmd->cache_data, target, mmd->shrink_type, mmd->shrink_mode, false))
{ {
@ -157,7 +157,8 @@ static void bake_modifier(Main * /*bmain*/,
/* Free data. */ /* Free data. */
if (mmd->cache_data) { if (mmd->cache_data) {
BKE_shrinkwrap_free_tree(mmd->cache_data); BKE_shrinkwrap_free_tree(mmd->cache_data);
MEM_SAFE_FREE(mmd->cache_data); MEM_delete(mmd->cache_data);
mmd->cache_data = nullptr;
} }
} }
} }
@ -172,7 +173,7 @@ static void free_data(GpencilModifierData *md)
ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md; ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
if (mmd->cache_data) { if (mmd->cache_data) {
BKE_shrinkwrap_free_tree(mmd->cache_data); BKE_shrinkwrap_free_tree(mmd->cache_data);
MEM_SAFE_FREE(mmd->cache_data); MEM_delete(mmd->cache_data);
} }
} }

View File

@ -467,7 +467,6 @@ void gpu_shader_create_info_init()
GPU_OS_ANY, GPU_OS_ANY,
GPU_DRIVER_ANY, GPU_DRIVER_ANY,
GPU_BACKEND_OPENGL) || GPU_BACKEND_OPENGL) ||
GPU_type_matches_ex(GPU_DEVICE_ANY, GPU_OS_MAC, GPU_DRIVER_ANY, GPU_BACKEND_OPENGL) ||
GPU_crappy_amd_driver()) GPU_crappy_amd_driver())
{ {
draw_modelmat = draw_modelmat_legacy; draw_modelmat = draw_modelmat_legacy;

View File

@ -1902,7 +1902,7 @@ void MSLGeneratorInterface::prepare_from_createinfo(const shader::ShaderCreateIn
case shader::ShaderCreateInfo::Resource::BindType::IMAGE: { case shader::ShaderCreateInfo::Resource::BindType::IMAGE: {
/* Flatten qualifier flags into final access state. */ /* Flatten qualifier flags into final access state. */
MSLTextureSamplerAccess access; MSLTextureSamplerAccess access;
if (bool(res.image.qualifiers & Qualifier::READ_WRITE)) { if ((res.image.qualifiers & Qualifier::READ_WRITE) == Qualifier::READ_WRITE) {
access = MSLTextureSamplerAccess::TEXTURE_ACCESS_READWRITE; access = MSLTextureSamplerAccess::TEXTURE_ACCESS_READWRITE;
} }
else if (bool(res.image.qualifiers & Qualifier::WRITE)) { else if (bool(res.image.qualifiers & Qualifier::WRITE)) {

View File

@ -437,6 +437,12 @@ static const char *load_face_element(PlyReadBuffer &file,
if (count < 1 || count > 255) { if (count < 1 || count > 255) {
return "Invalid face size, must be between 1 and 255"; return "Invalid face size, must be between 1 and 255";
} }
/* Previous python based importer was accepting faces with fewer
* than 3 vertices, and silently dropping them. */
if (count < 3) {
fprintf(stderr, "PLY Importer: ignoring face %i (%i vertices)\n", i, count);
continue;
}
for (int j = 0; j < count; j++) { for (int j = 0; j < count; j++) {
int index; int index;
@ -467,15 +473,22 @@ static const char *load_face_element(PlyReadBuffer &file,
scratch.resize(count * data_type_size[prop.type]); scratch.resize(count * data_type_size[prop.type]);
file.read_bytes(scratch.data(), scratch.size()); file.read_bytes(scratch.data(), scratch.size());
ptr = scratch.data(); /* Previous python based importer was accepting faces with fewer
if (header.type == PlyFormatType::BINARY_BE) { * than 3 vertices, and silently dropping them. */
endian_switch_array((uint8_t *)ptr, data_type_size[prop.type], count); if (count < 3) {
fprintf(stderr, "PLY Importer: ignoring face %i (%i vertices)\n", i, count);
} }
for (int j = 0; j < count; ++j) { else {
uint32_t index = get_binary_value<uint32_t>(prop.type, ptr); ptr = scratch.data();
data->face_vertices.append(index); if (header.type == PlyFormatType::BINARY_BE) {
endian_switch_array((uint8_t *)ptr, data_type_size[prop.type], count);
}
for (int j = 0; j < count; ++j) {
uint32_t index = get_binary_value<uint32_t>(prop.type, ptr);
data->face_vertices.append(index);
}
data->face_sizes.append(count);
} }
data->face_sizes.append(count);
/* Skip any properties after vertex indices. */ /* Skip any properties after vertex indices. */
for (int j = prop_index + 1; j < element.properties.size(); j++) { for (int j = prop_index + 1; j < element.properties.size(); j++) {

View File

@ -909,8 +909,7 @@ void USDMeshReader::read_custom_data(const ImportSettings *settings,
/* To avoid unnecessarily reloading static primvars during animation, /* To avoid unnecessarily reloading static primvars during animation,
* early out if not first load and this primvar isn't animated. */ * early out if not first load and this primvar isn't animated. */
const bool is_time_varying = primvar_varying_map_.lookup_default(name, false); if (!new_mesh && primvar_varying_map_.contains(name) && !primvar_varying_map_.lookup(name)) {
if (!new_mesh && !is_time_varying) {
continue; continue;
} }

View File

@ -69,11 +69,6 @@ set(SRC
dna_utils.cc dna_utils.cc
makesdna.cc makesdna.cc
${SRC_BLENLIB} ${SRC_BLENLIB}
../../../../intern/guardedalloc/intern/leak_detector.cc
../../../../intern/guardedalloc/intern/mallocn.c
../../../../intern/guardedalloc/intern/mallocn_guarded_impl.c
../../../../intern/guardedalloc/intern/mallocn_lockfree_impl.c
../../../../intern/guardedalloc/intern/memory_usage.cc
${dna_header_include_file} ${dna_header_include_file}
${dna_header_string_file} ${dna_header_string_file}
) )

View File

@ -222,12 +222,6 @@ set(SRC
${DEFSRC} ${DEFSRC}
${APISRC} ${APISRC}
../../../../intern/clog/clog.c ../../../../intern/clog/clog.c
../../../../intern/guardedalloc/intern/leak_detector.cc
../../../../intern/guardedalloc/intern/mallocn.c
../../../../intern/guardedalloc/intern/mallocn_guarded_impl.c
../../../../intern/guardedalloc/intern/mallocn_lockfree_impl.c
../../../../intern/guardedalloc/intern/memory_usage.cc
# Needed for defaults. # Needed for defaults.
../../../../release/datafiles/userdef/userdef_default.c ../../../../release/datafiles/userdef/userdef_default.c
../../../../release/datafiles/userdef/userdef_default_theme.c ../../../../release/datafiles/userdef/userdef_default_theme.c

View File

@ -74,7 +74,7 @@ static void free_data(ModifierData *md)
if (smd->cache_data) { if (smd->cache_data) {
BKE_shrinkwrap_free_tree(smd->cache_data); BKE_shrinkwrap_free_tree(smd->cache_data);
MEM_SAFE_FREE(smd->cache_data); MEM_delete(smd->cache_data);
} }
} }
@ -196,17 +196,18 @@ static void ensure_shrinkwrap_cache_data(GreasePencilShrinkwrapModifierData &smd
{ {
if (smd.cache_data) { if (smd.cache_data) {
BKE_shrinkwrap_free_tree(smd.cache_data); BKE_shrinkwrap_free_tree(smd.cache_data);
MEM_SAFE_FREE(smd.cache_data); MEM_delete(smd.cache_data);
smd.cache_data = nullptr;
} }
Object *target_ob = DEG_get_evaluated_object(ctx.depsgraph, smd.target); Object *target_ob = DEG_get_evaluated_object(ctx.depsgraph, smd.target);
Mesh *target_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(target_ob); Mesh *target_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(target_ob);
smd.cache_data = static_cast<ShrinkwrapTreeData *>( smd.cache_data = MEM_new<ShrinkwrapTreeData>(__func__);
MEM_callocN(sizeof(ShrinkwrapTreeData), __func__));
const bool tree_ok = BKE_shrinkwrap_init_tree( const bool tree_ok = BKE_shrinkwrap_init_tree(
smd.cache_data, target_mesh, smd.shrink_type, smd.shrink_mode, false); smd.cache_data, target_mesh, smd.shrink_type, smd.shrink_mode, false);
if (!tree_ok) { if (!tree_ok) {
MEM_SAFE_FREE(smd.cache_data); MEM_delete(smd.cache_data);
smd.cache_data = nullptr;
} }
} }

View File

@ -14,7 +14,9 @@ static void node_declare(NodeDeclarationBuilder &b)
{ {
b.is_function_node(); b.is_function_node();
b.add_input<decl::Matrix>("Matrix"); b.add_input<decl::Matrix>("Matrix");
b.add_output<decl::Matrix>("Matrix"); b.add_output<decl::Matrix>("Matrix").description(
"The inverted matrix or the identity matrix if the input is not invertable");
b.add_output<decl::Bool>("Invertable").description("True if the input matrix is invertable");
} }
static void search_link_ops(GatherLinkSearchOpParams &params) static void search_link_ops(GatherLinkSearchOpParams &params)
@ -24,10 +26,45 @@ static void search_link_ops(GatherLinkSearchOpParams &params)
} }
} }
class InvertMatrixFunction : public mf::MultiFunction {
public:
InvertMatrixFunction()
{
static mf::Signature signature = []() {
mf::Signature signature;
mf::SignatureBuilder builder{"Invert Matrix", signature};
builder.single_input<float4x4>("Matrix");
builder.single_output<float4x4>("Matrix", mf::ParamFlag::SupportsUnusedOutput);
builder.single_output<bool>("Invertable", mf::ParamFlag::SupportsUnusedOutput);
return signature;
}();
this->set_signature(&signature);
}
void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override
{
const VArraySpan<float4x4> in_matrices = params.readonly_single_input<float4x4>(0, "Matrix");
MutableSpan<float4x4> out_matrices = params.uninitialized_single_output_if_required<float4x4>(
1, "Matrix");
MutableSpan<bool> out_invertable = params.uninitialized_single_output_if_required<bool>(
2, "Invertable");
mask.foreach_index([&](const int64_t i) {
const float4x4 &matrix = in_matrices[i];
bool success;
float4x4 inverted_matrix = math::invert(matrix, success);
if (!out_matrices.is_empty()) {
out_matrices[i] = success ? inverted_matrix : float4x4::identity();
}
if (!out_invertable.is_empty()) {
out_invertable[i] = success;
}
});
}
};
static void node_build_multi_function(NodeMultiFunctionBuilder &builder) static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{ {
static auto fn = mf::build::SI1_SO<float4x4, float4x4>( static InvertMatrixFunction fn;
"Invert Matrix", [](float4x4 matrix) { return math::invert(matrix); });
builder.set_matching_fn(fn); builder.set_matching_fn(fn);
} }

View File

@ -46,7 +46,7 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>("Points").propagate_all(); b.add_output<decl::Geometry>("Points").propagate_all();
b.add_output<decl::Vector>("Tangent").field_on_all(); b.add_output<decl::Vector>("Tangent").field_on_all();
b.add_output<decl::Vector>("Normal").field_on_all(); b.add_output<decl::Vector>("Normal").field_on_all();
b.add_output<decl::Vector>("Rotation").field_on_all(); b.add_output<decl::Rotation>("Rotation").field_on_all();
} }
static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
@ -76,12 +76,12 @@ static void node_update(bNodeTree *ntree, bNode *node)
static void fill_rotation_attribute(const Span<float3> tangents, static void fill_rotation_attribute(const Span<float3> tangents,
const Span<float3> normals, const Span<float3> normals,
MutableSpan<float3> rotations) MutableSpan<math::Quaternion> rotations)
{ {
threading::parallel_for(IndexRange(rotations.size()), 512, [&](IndexRange range) { threading::parallel_for(IndexRange(rotations.size()), 512, [&](IndexRange range) {
for (const int i : range) { for (const int i : range) {
rotations[i] = float3( rotations[i] = math::to_quaternion(
math::to_euler(math::from_orthonormal_axes<float4x4>(normals[i], tangents[i]))); math::from_orthonormal_axes<float4x4>(normals[i], tangents[i]));
} }
}); });
} }
@ -121,8 +121,9 @@ static PointCloud *pointcloud_from_curves(bke::CurvesGeometry curves,
MutableAttributeAccessor attributes = curves.attributes_for_write(); MutableAttributeAccessor attributes = curves.attributes_for_write();
const VArraySpan tangents = *attributes.lookup<float3>(tangent_id, AttrDomain::Point); const VArraySpan tangents = *attributes.lookup<float3>(tangent_id, AttrDomain::Point);
const VArraySpan normals = *attributes.lookup<float3>(normal_id, AttrDomain::Point); const VArraySpan normals = *attributes.lookup<float3>(normal_id, AttrDomain::Point);
SpanAttributeWriter<float3> rotations = attributes.lookup_or_add_for_write_only_span<float3>( SpanAttributeWriter<math::Quaternion> rotations =
rotation_id, AttrDomain::Point); attributes.lookup_or_add_for_write_only_span<math::Quaternion>(rotation_id,
AttrDomain::Point);
fill_rotation_attribute(tangents, normals, rotations.span); fill_rotation_attribute(tangents, normals, rotations.span);
rotations.finish(); rotations.finish();
} }

View File

@ -333,29 +333,10 @@ if(WITH_PYTHON_MODULE)
else() else()
add_executable(blender ${EXETYPE} ${SRC}) add_executable(blender ${EXETYPE} ${SRC})
if(WITH_CPU_CHECK) if(WITH_CPU_CHECK)
target_compile_definitions(blender PRIVATE WITH_CPU_CHECK)
# we cannot directly link against any blender libraries for the cpu_check module
# as they may have been build for an ISA that is unsupported by the CPU
# running this code.
add_library(blender_cpu_check SHARED
creator_cpu_check.cc
)
target_link_libraries(blender_cpu_check
PRIVATE ${PLATFORM_LINKLIBS}
)
# blender_cpu_check *NEEDS* to be linked first, there can be no exceptions # blender_cpu_check *NEEDS* to be linked first, there can be no exceptions
# to this, this is to ensure this will be the first code to run once the # to this, this is to ensure this will be the first code to run once the
# blender binary has been loaded by the OS. # blender binary has been loaded by the OS.
target_link_libraries(blender PRIVATE blender_cpu_check) target_link_libraries(blender PRIVATE blender_cpu_check)
if(NOT WIN32)
set(_LIB_SUB_FOLDER "lib/")
endif()
set_target_properties(blender_cpu_check
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/${_LIB_SUB_FOLDER}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/${_LIB_SUB_FOLDER}"
)
unset(_LIB_SUB_FOLDER)
endif() endif()
if(WIN32) if(WIN32)
add_executable(blender-launcher WIN32 add_executable(blender-launcher WIN32