WIP: Brush assets project #106303
|
@ -1399,13 +1399,12 @@ endif()
|
|||
|
||||
# Test SIMD support, before platform includes to determine if sse2neon is needed.
|
||||
if(WITH_CPU_SIMD)
|
||||
set(COMPILER_SSE_FLAG)
|
||||
set(COMPILER_SSE2_FLAG)
|
||||
set(COMPILER_SSE42_FLAG)
|
||||
|
||||
# Test Neon first since macOS Arm can compile and run x86-64 SSE binaries.
|
||||
test_neon_support()
|
||||
if(NOT SUPPORT_NEON_BUILD)
|
||||
test_sse_support(COMPILER_SSE_FLAG COMPILER_SSE2_FLAG)
|
||||
test_sse_support(COMPILER_SSE42_FLAG)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
@ -1445,8 +1444,6 @@ endif()
|
|||
|
||||
# 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(SUPPORT_NEON_BUILD)
|
||||
# Neon
|
||||
|
@ -1456,15 +1453,20 @@ if(WITH_CPU_SIMD)
|
|||
endif()
|
||||
else()
|
||||
# SSE
|
||||
if(SUPPORT_SSE_BUILD)
|
||||
string(PREPEND PLATFORM_CFLAGS "${COMPILER_SSE_FLAG} ")
|
||||
add_definitions(-D__SSE__ -D__MMX__)
|
||||
endif()
|
||||
if(SUPPORT_SSE2_BUILD)
|
||||
string(APPEND PLATFORM_CFLAGS " ${COMPILER_SSE2_FLAG}")
|
||||
add_definitions(-D__SSE2__)
|
||||
if(NOT SUPPORT_SSE_BUILD) # don't double up
|
||||
add_definitions(-D__MMX__)
|
||||
if(SUPPORT_SSE42_BUILD)
|
||||
string(APPEND CMAKE_CXX_FLAGS " ${COMPILER_SSE42_FLAG}")
|
||||
string(APPEND CMAKE_C_FLAGS " ${COMPILER_SSE42_FLAG}")
|
||||
# MSVC doesn't define any of these and only does the AVX and higher flags.
|
||||
# For consistency we define these flags for MSVC.
|
||||
if(WIN32)
|
||||
add_compile_definitions(
|
||||
__MMX__
|
||||
__SSE__
|
||||
__SSE2__
|
||||
__SSE3__
|
||||
__SSE4_1__
|
||||
__SSE4_2__
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
@ -1479,10 +1481,8 @@ if(FIRST_RUN)
|
|||
else()
|
||||
message(STATUS "Neon SIMD instructions detected but unused, requires sse2neon")
|
||||
endif()
|
||||
elseif(SUPPORT_SSE2_BUILD)
|
||||
message(STATUS "SSE2 SIMD instructions enabled")
|
||||
elseif(SUPPORT_SSE_BUILD)
|
||||
message(STATUS "SSE SIMD instructions enabled")
|
||||
elseif(SUPPORT_SSE42_BUILD)
|
||||
message(STATUS "SSE42 SIMD instructions enabled")
|
||||
else()
|
||||
message(STATUS "No SIMD instructions detected")
|
||||
endif()
|
||||
|
|
|
@ -540,49 +540,37 @@ function(setup_platform_linker_libs
|
|||
endfunction()
|
||||
|
||||
macro(TEST_SSE_SUPPORT
|
||||
_sse_flags
|
||||
_sse2_flags)
|
||||
_sse42_flags)
|
||||
|
||||
include(CheckCSourceRuns)
|
||||
|
||||
# message(STATUS "Detecting SSE support")
|
||||
if(CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang"))
|
||||
set(${_sse_flags} "-msse")
|
||||
set(${_sse2_flags} "-msse2")
|
||||
set(${_sse42_flags} "-march=x86-64-v2")
|
||||
elseif(MSVC)
|
||||
# x86_64 has this auto enabled
|
||||
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
|
||||
set(${_sse_flags} "")
|
||||
set(${_sse2_flags} "")
|
||||
else()
|
||||
set(${_sse_flags} "/arch:SSE")
|
||||
set(${_sse2_flags} "/arch:SSE2")
|
||||
endif()
|
||||
# msvc has no specific build flags for SSE42, but when using intrinsics it will
|
||||
# generate the right instructions.
|
||||
set(${_sse42_flags} "")
|
||||
elseif(CMAKE_C_COMPILER_ID STREQUAL "Intel")
|
||||
set(${_sse_flags} "") # icc defaults to -msse
|
||||
set(${_sse2_flags} "") # icc defaults to -msse2
|
||||
if(WIN32)
|
||||
set(${_sse42_flags} "/QxSSE4.2")
|
||||
else()
|
||||
set(${_sse42_flags} "-xsse4.2")
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "SSE flags for this compiler: '${CMAKE_C_COMPILER_ID}' not known")
|
||||
set(${_sse_flags})
|
||||
set(${_sse2_flags})
|
||||
set(${_sse42_flags})
|
||||
endif()
|
||||
|
||||
set(CMAKE_REQUIRED_FLAGS "${${_sse_flags}} ${${_sse2_flags}}")
|
||||
set(CMAKE_REQUIRED_FLAGS "${${_sse42_flags}}")
|
||||
|
||||
if(NOT DEFINED SUPPORT_SSE_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)
|
||||
if(NOT DEFINED SUPPORT_SSE42_BUILD)
|
||||
# result cached
|
||||
check_c_source_runs("
|
||||
#include <nmmintrin.h>
|
||||
#include <emmintrin.h>
|
||||
int main(void) { __m128d v = _mm_setzero_pd(); return 0; }"
|
||||
SUPPORT_SSE2_BUILD)
|
||||
int main(void) { __m128i v = _mm_setzero_si128(); v = _mm_cmpgt_epi64(v,v); return 0; }"
|
||||
SUPPORT_SSE42_BUILD)
|
||||
endif()
|
||||
|
||||
unset(CMAKE_REQUIRED_FLAGS)
|
||||
|
|
|
@ -181,3 +181,7 @@ endif()
|
|||
if(WITH_FREESTYLE)
|
||||
add_subdirectory(freestyle)
|
||||
endif()
|
||||
|
||||
if(WITH_CPU_CHECK)
|
||||
add_subdirectory(cpucheck)
|
||||
endif()
|
||||
|
|
|
@ -582,14 +582,6 @@ struct SculptSession {
|
|||
blender::float3 cursor_sampled_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 */
|
||||
RegionView3D *rv3d;
|
||||
View3D *v3d;
|
||||
|
|
|
@ -98,18 +98,19 @@ void BKE_gpencil_cache_data_init(Depsgraph *depsgraph, Object *ob)
|
|||
}
|
||||
if (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);
|
||||
Mesh *target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target);
|
||||
mmd->cache_data = static_cast<ShrinkwrapTreeData *>(
|
||||
MEM_callocN(sizeof(ShrinkwrapTreeData), __func__));
|
||||
mmd->cache_data = MEM_new<ShrinkwrapTreeData>(__func__);
|
||||
if (BKE_shrinkwrap_init_tree(
|
||||
mmd->cache_data, target, mmd->shrink_type, mmd->shrink_mode, false))
|
||||
{
|
||||
}
|
||||
else {
|
||||
MEM_SAFE_FREE(mmd->cache_data);
|
||||
MEM_delete(mmd->cache_data);
|
||||
mmd->cache_data = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -136,7 +137,8 @@ void BKE_gpencil_cache_data_clear(Object *ob)
|
|||
ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
|
||||
if ((mmd) && (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;
|
||||
}
|
||||
|
|
|
@ -321,11 +321,17 @@ void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf,
|
|||
bool has_bezier_stroke = false;
|
||||
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf.strokes) {
|
||||
if (gps->editcurve != nullptr) {
|
||||
if (gps->editcurve->tot_curve_points == 0) {
|
||||
continue;
|
||||
}
|
||||
has_bezier_stroke = true;
|
||||
num_points += gps->editcurve->tot_curve_points;
|
||||
curve_types.append(CURVE_TYPE_BEZIER);
|
||||
}
|
||||
else {
|
||||
if (gps->totpoints == 0) {
|
||||
continue;
|
||||
}
|
||||
num_points += gps->totpoints;
|
||||
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);
|
||||
}
|
||||
|
||||
/* Return if the legacy frame contains no strokes (or zero points). */
|
||||
if (num_strokes == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Resize the CurvesGeometry. */
|
||||
Drawing &drawing = r_drawing.wrap();
|
||||
CurvesGeometry &curves = drawing.strokes_for_write();
|
||||
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();
|
||||
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);
|
||||
|
||||
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;
|
||||
/* TODO: This should be a `double` attribute. */
|
||||
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_materials.span[stroke_i] = gps->mat_nr;
|
||||
|
||||
IndexRange points = points_by_curve[stroke_i];
|
||||
if (points.is_empty()) {
|
||||
continue;
|
||||
}
|
||||
const IndexRange points = points_by_curve[stroke_i];
|
||||
BLI_assert(points.size() == 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`
|
||||
|
@ -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);
|
||||
legacy_texture_matrices[stroke_i] = legacy_texture_matrix;
|
||||
|
||||
stroke_i++;
|
||||
}
|
||||
|
||||
/* Ensure that the normals are up to date. */
|
||||
|
|
|
@ -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)
|
|
@ -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. */
|
||||
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
|
||||
|
||||
/* Execute Compositor render commands. */
|
||||
|
|
|
@ -3259,14 +3259,6 @@ void DRW_gpu_context_enable_ex(bool /*restore*/)
|
|||
void DRW_gpu_context_disable_ex(bool restore)
|
||||
{
|
||||
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) {
|
||||
wm_window_reset_drawable();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1105,20 +1105,6 @@ void UI_widgetbase_draw_cache_end()
|
|||
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)
|
||||
{
|
||||
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.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.count++;
|
||||
|
||||
|
|
|
@ -284,16 +284,6 @@ void immDrawPixelsTexTiled_scaling_clipping(IMMDrawPixelsTexState *state,
|
|||
immAttr2f(texco, left / float(tex_w), top / float(tex_h));
|
||||
immVertex2f(pos, rast_x + offset_left * xzoom, rast_y + top * yzoom * scaleY);
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "sculpt_intern.hh"
|
||||
|
||||
namespace blender::ed::sculpt_paint::trim {
|
||||
|
||||
enum class OperationType {
|
||||
Intersect = 0,
|
||||
Difference = 1,
|
||||
|
@ -105,20 +106,24 @@ static EnumPropertyItem solver_modes[] = {
|
|||
struct TrimOperation {
|
||||
gesture::Operation op;
|
||||
|
||||
/* Operation-generated geometry. */
|
||||
Mesh *mesh;
|
||||
float (*true_mesh_co)[3];
|
||||
|
||||
float depth_front;
|
||||
float depth_back;
|
||||
|
||||
/* Operator properties. */
|
||||
bool use_cursor_depth;
|
||||
|
||||
bool initial_hit;
|
||||
blender::float3 initial_location;
|
||||
blender::float3 initial_normal;
|
||||
|
||||
OperationType mode;
|
||||
SolverMode solver_mode;
|
||||
OrientationType orientation;
|
||||
ExtrudeMode extrude_mode;
|
||||
};
|
||||
|
||||
/* Recalculate the mesh normals for the generated trim mesh. */
|
||||
static void update_normals(gesture::GestureData &gesture_data)
|
||||
{
|
||||
TrimOperation *trim_operation = (TrimOperation *)gesture_data.operation;
|
||||
|
@ -151,8 +156,8 @@ static void update_normals(gesture::GestureData &gesture_data)
|
|||
trim_operation->mesh = result;
|
||||
}
|
||||
|
||||
/* Get the origin and normal that are going to be used for calculating the depth and position the
|
||||
* trimming geometry. */
|
||||
/* Get the origin and normal that are going to be used for calculating the depth and position of
|
||||
* the trimming geometry. */
|
||||
static void get_origin_and_normal(gesture::GestureData &gesture_data,
|
||||
float *r_origin,
|
||||
float *r_normal)
|
||||
|
@ -166,23 +171,26 @@ static void get_origin_and_normal(gesture::GestureData &gesture_data,
|
|||
case OrientationType::View:
|
||||
mul_v3_m4v3(r_origin,
|
||||
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);
|
||||
negate_v3(r_normal);
|
||||
break;
|
||||
case OrientationType::Surface:
|
||||
mul_v3_m4v3(r_origin,
|
||||
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
|
||||
* 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);
|
||||
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;
|
||||
|
||||
|
@ -197,8 +205,8 @@ static void calculate_depth(gesture::GestureData &gesture_data)
|
|||
get_origin_and_normal(gesture_data, shape_origin, shape_normal);
|
||||
plane_from_point_normal_v3(shape_plane, shape_origin, shape_normal);
|
||||
|
||||
trim_operation->depth_front = FLT_MAX;
|
||||
trim_operation->depth_back = -FLT_MAX;
|
||||
float depth_front = FLT_MAX;
|
||||
float depth_back = -FLT_MAX;
|
||||
|
||||
for (int i = 0; i < totvert; 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];
|
||||
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);
|
||||
trim_operation->depth_front = min_ff(dist, trim_operation->depth_front);
|
||||
trim_operation->depth_back = max_ff(dist, trim_operation->depth_back);
|
||||
depth_front = min_ff(dist, depth_front);
|
||||
depth_back = max_ff(dist, depth_back);
|
||||
}
|
||||
|
||||
if (trim_operation->use_cursor_depth) {
|
||||
float world_space_gesture_initial_location[3];
|
||||
mul_v3_m4v3(world_space_gesture_initial_location,
|
||||
vc->obact->object_to_world().ptr(),
|
||||
ss->gesture_initial_location);
|
||||
trim_operation->initial_location);
|
||||
|
||||
float mid_point_depth;
|
||||
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,
|
||||
shape_plane) :
|
||||
(trim_operation->depth_back + trim_operation->depth_front) * 0.5f;
|
||||
(depth_back + depth_front) * 0.5f;
|
||||
}
|
||||
else {
|
||||
/* 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
|
||||
* surface. */
|
||||
mid_point_depth = ss->gesture_initial_hit ?
|
||||
0.0f :
|
||||
(trim_operation->depth_back + trim_operation->depth_front) * 0.5f;
|
||||
mid_point_depth = trim_operation->initial_hit ? 0.0f : (depth_back + depth_front) * 0.5f;
|
||||
}
|
||||
|
||||
float depth_radius;
|
||||
|
||||
if (ss->gesture_initial_hit) {
|
||||
if (trim_operation->initial_hit) {
|
||||
depth_radius = ss->cursor_radius;
|
||||
}
|
||||
else {
|
||||
|
@ -253,16 +259,19 @@ static void calculate_depth(gesture::GestureData &gesture_data)
|
|||
|
||||
if (!BKE_brush_use_locked_size(scene, brush)) {
|
||||
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 {
|
||||
depth_radius = BKE_brush_unprojected_radius_get(scene, brush);
|
||||
}
|
||||
}
|
||||
|
||||
trim_operation->depth_front = mid_point_depth - depth_radius;
|
||||
trim_operation->depth_back = mid_point_depth + depth_radius;
|
||||
depth_front = 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)
|
||||
|
@ -281,20 +290,6 @@ static void generate_geometry(gesture::GestureData &gesture_data)
|
|||
trim_operation->true_mesh_co = static_cast<float(*)[3]>(
|
||||
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_normal[3];
|
||||
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. */
|
||||
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];
|
||||
|
||||
/* Get origin point for OrientationType::View.
|
||||
|
@ -436,11 +445,16 @@ static void generate_geometry(gesture::GestureData &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;
|
||||
BKE_id_free(nullptr, trim_operation->mesh);
|
||||
MEM_freeN(trim_operation->true_mesh_co);
|
||||
Object *object = gesture_data.vc.obact;
|
||||
SculptSession *ss = object->sculpt;
|
||||
|
||||
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*/)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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"));
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
"trim_mode",
|
||||
operation_types,
|
||||
|
@ -669,21 +691,26 @@ static bool can_exec(const bContext &C)
|
|||
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);
|
||||
SculptSession &ss = *ob.sculpt;
|
||||
|
||||
SCULPT_vertex_random_access_ensure(&ss);
|
||||
|
||||
SculptCursorGeometryInfo sgi;
|
||||
const float mval_fl[2] = {float(event->mval[0]), float(event->mval[1])};
|
||||
int mval[2];
|
||||
RNA_int_get_array(op.ptr, "location", mval);
|
||||
|
||||
/* TODO: Remove gesture_* properties from SculptSession */
|
||||
ss.gesture_initial_hit = SCULPT_cursor_geometry_info_update(&C, &sgi, mval_fl, false);
|
||||
if (ss.gesture_initial_hit) {
|
||||
copy_v3_v3(ss.gesture_initial_location, sgi.location);
|
||||
copy_v3_v3(ss.gesture_initial_normal, sgi.normal);
|
||||
SculptCursorGeometryInfo sgi;
|
||||
const float mval_fl[2] = {float(mval[0]), float(mval[1])};
|
||||
|
||||
TrimOperation *trim_operation = (TrimOperation *)gesture_data.operation;
|
||||
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;
|
||||
}
|
||||
|
||||
initialize_cursor_info(*C, *op, *gesture_data);
|
||||
init_operation(*gesture_data, *op);
|
||||
|
||||
gesture::apply(*C, *gesture_data, *op);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
@ -709,7 +738,7 @@ static int gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|||
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);
|
||||
}
|
||||
|
@ -724,7 +753,10 @@ static int gesture_lasso_exec(bContext *C, wmOperator *op)
|
|||
if (!gesture_data) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
initialize_cursor_info(*C, *op, *gesture_data);
|
||||
init_operation(*gesture_data, *op);
|
||||
|
||||
gesture::apply(*C, *gesture_data, *op);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
@ -735,7 +767,7 @@ static int gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *even
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -1332,7 +1332,8 @@ static void create_inspection_string_for_generic_value(const bNodeSocket &socket
|
|||
((*static_cast<bool *>(socket_value)) ? TIP_("True") : TIP_("False")));
|
||||
}
|
||||
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[1] << ",\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,
|
||||
const nodes::decl::Geometry *socket_decl,
|
||||
const bool after_log)
|
||||
const nodes::decl::Geometry *socket_decl)
|
||||
{
|
||||
/* 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. */
|
||||
|
@ -1489,10 +1489,6 @@ static void create_inspection_string_for_geometry_socket(std::stringstream &ss,
|
|||
return;
|
||||
}
|
||||
|
||||
if (after_log) {
|
||||
ss << ".\n\n";
|
||||
}
|
||||
|
||||
Span<bke::GeometryComponent::Type> supported_types = socket_decl->supported_types();
|
||||
if (supported_types.is_empty()) {
|
||||
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(
|
||||
geo_log::GeoTreeLog &geo_tree_log, const bNodeSocket &socket)
|
||||
static std::optional<std::string> create_description_inspection_string(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;
|
||||
|
||||
if (geo_tree_log == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (socket.typeinfo->base_cpp_type == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
geo_tree_log.ensure_socket_values();
|
||||
ValueLog *value_log = geo_tree_log.find_socket_value_log(socket);
|
||||
geo_tree_log->ensure_socket_values();
|
||||
ValueLog *value_log = geo_tree_log->find_socket_value_log(socket);
|
||||
std::stringstream ss;
|
||||
if (const geo_log::GenericValueLog *generic_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);
|
||||
}
|
||||
|
||||
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 *>(
|
||||
socket.runtime->declaration))
|
||||
{
|
||||
const bool after_log = value_log != nullptr;
|
||||
create_inspection_string_for_geometry_socket(ss, socket_decl, after_log);
|
||||
create_inspection_string_for_geometry_socket(ss, socket_decl);
|
||||
}
|
||||
|
||||
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 * {
|
||||
const bNodeTreeZones *zones = ntree.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);
|
||||
}();
|
||||
|
||||
if (ntree.type == NTREE_GEOMETRY && geo_tree_log != nullptr) {
|
||||
if (!output.str().empty()) {
|
||||
Vector<std::string> inspection_strings;
|
||||
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::string> socket_inspection_str = create_socket_inspection_string(
|
||||
*geo_tree_log, socket);
|
||||
if (socket_inspection_str.has_value()) {
|
||||
output << *socket_inspection_str;
|
||||
if (inspection_strings.is_empty()) {
|
||||
const bNode &node = socket.owner_node();
|
||||
if (node.is_reroute()) {
|
||||
char reroute_name[MAX_NAME];
|
||||
bke::nodeLabel(&ntree, &node, reroute_name, sizeof(reroute_name));
|
||||
output << reroute_name;
|
||||
}
|
||||
else {
|
||||
output << bke::nodeSocketLabel(&socket);
|
||||
}
|
||||
|
||||
if (ntree.type == NTREE_GEOMETRY) {
|
||||
output << ".\n\n";
|
||||
output << TIP_(
|
||||
"Unknown socket value. Either the socket was not used or its value was not logged "
|
||||
"during the last evaluation");
|
||||
}
|
||||
}
|
||||
|
||||
if (output.str().empty()) {
|
||||
output << bke::nodeSocketLabel(&socket);
|
||||
}
|
||||
|
||||
return output.str();
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_math_quaternion_types.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
|
||||
|
@ -395,7 +396,8 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
|
|||
UI_but_func_tooltip_set(
|
||||
but,
|
||||
[](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;
|
||||
ss << value[0] << ",\n";
|
||||
ss << value[1] << ",\n";
|
||||
|
|
|
@ -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
|
||||
* edge. */
|
||||
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) {
|
||||
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);
|
||||
/* Allow ignoring multiple triangle intersections if the uv is almost exactly on an edge. */
|
||||
if (worse_dist < -edge_epsilon) {
|
||||
/* The uv sample is in multiple triangles. */
|
||||
return Result{ResultType::Multiple};
|
||||
const int3 &best_tri = corner_tris_[tri_i];
|
||||
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};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -139,12 +139,12 @@ static void bake_modifier(Main * /*bmain*/,
|
|||
/* Recalculate shrinkwrap data. */
|
||||
if (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);
|
||||
Mesh *target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target);
|
||||
mmd->cache_data = static_cast<ShrinkwrapTreeData *>(
|
||||
MEM_callocN(sizeof(ShrinkwrapTreeData), __func__));
|
||||
mmd->cache_data = MEM_new<ShrinkwrapTreeData>(__func__);
|
||||
if (BKE_shrinkwrap_init_tree(
|
||||
mmd->cache_data, target, mmd->shrink_type, mmd->shrink_mode, false))
|
||||
{
|
||||
|
@ -157,7 +157,8 @@ static void bake_modifier(Main * /*bmain*/,
|
|||
/* Free data. */
|
||||
if (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;
|
||||
if (mmd->cache_data) {
|
||||
BKE_shrinkwrap_free_tree(mmd->cache_data);
|
||||
MEM_SAFE_FREE(mmd->cache_data);
|
||||
MEM_delete(mmd->cache_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -467,7 +467,6 @@ void gpu_shader_create_info_init()
|
|||
GPU_OS_ANY,
|
||||
GPU_DRIVER_ANY,
|
||||
GPU_BACKEND_OPENGL) ||
|
||||
GPU_type_matches_ex(GPU_DEVICE_ANY, GPU_OS_MAC, GPU_DRIVER_ANY, GPU_BACKEND_OPENGL) ||
|
||||
GPU_crappy_amd_driver())
|
||||
{
|
||||
draw_modelmat = draw_modelmat_legacy;
|
||||
|
|
|
@ -1902,7 +1902,7 @@ void MSLGeneratorInterface::prepare_from_createinfo(const shader::ShaderCreateIn
|
|||
case shader::ShaderCreateInfo::Resource::BindType::IMAGE: {
|
||||
/* Flatten qualifier flags into final access state. */
|
||||
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;
|
||||
}
|
||||
else if (bool(res.image.qualifiers & Qualifier::WRITE)) {
|
||||
|
|
|
@ -437,6 +437,12 @@ static const char *load_face_element(PlyReadBuffer &file,
|
|||
if (count < 1 || count > 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++) {
|
||||
int index;
|
||||
|
@ -467,15 +473,22 @@ static const char *load_face_element(PlyReadBuffer &file,
|
|||
|
||||
scratch.resize(count * data_type_size[prop.type]);
|
||||
file.read_bytes(scratch.data(), scratch.size());
|
||||
ptr = scratch.data();
|
||||
if (header.type == PlyFormatType::BINARY_BE) {
|
||||
endian_switch_array((uint8_t *)ptr, data_type_size[prop.type], count);
|
||||
/* 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);
|
||||
}
|
||||
for (int j = 0; j < count; ++j) {
|
||||
uint32_t index = get_binary_value<uint32_t>(prop.type, ptr);
|
||||
data->face_vertices.append(index);
|
||||
else {
|
||||
ptr = scratch.data();
|
||||
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. */
|
||||
for (int j = prop_index + 1; j < element.properties.size(); j++) {
|
||||
|
|
|
@ -909,8 +909,7 @@ void USDMeshReader::read_custom_data(const ImportSettings *settings,
|
|||
|
||||
/* To avoid unnecessarily reloading static primvars during animation,
|
||||
* 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 && !is_time_varying) {
|
||||
if (!new_mesh && primvar_varying_map_.contains(name) && !primvar_varying_map_.lookup(name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -69,11 +69,6 @@ set(SRC
|
|||
dna_utils.cc
|
||||
makesdna.cc
|
||||
${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_string_file}
|
||||
)
|
||||
|
|
|
@ -222,12 +222,6 @@ set(SRC
|
|||
${DEFSRC}
|
||||
${APISRC}
|
||||
../../../../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.
|
||||
../../../../release/datafiles/userdef/userdef_default.c
|
||||
../../../../release/datafiles/userdef/userdef_default_theme.c
|
||||
|
|
|
@ -74,7 +74,7 @@ static void free_data(ModifierData *md)
|
|||
|
||||
if (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) {
|
||||
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);
|
||||
Mesh *target_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(target_ob);
|
||||
|
||||
smd.cache_data = static_cast<ShrinkwrapTreeData *>(
|
||||
MEM_callocN(sizeof(ShrinkwrapTreeData), __func__));
|
||||
smd.cache_data = MEM_new<ShrinkwrapTreeData>(__func__);
|
||||
const bool tree_ok = BKE_shrinkwrap_init_tree(
|
||||
smd.cache_data, target_mesh, smd.shrink_type, smd.shrink_mode, false);
|
||||
if (!tree_ok) {
|
||||
MEM_SAFE_FREE(smd.cache_data);
|
||||
MEM_delete(smd.cache_data);
|
||||
smd.cache_data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,9 @@ static void node_declare(NodeDeclarationBuilder &b)
|
|||
{
|
||||
b.is_function_node();
|
||||
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 ¶ms)
|
||||
|
@ -24,10 +26,45 @@ static void search_link_ops(GatherLinkSearchOpParams ¶ms)
|
|||
}
|
||||
}
|
||||
|
||||
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 auto fn = mf::build::SI1_SO<float4x4, float4x4>(
|
||||
"Invert Matrix", [](float4x4 matrix) { return math::invert(matrix); });
|
||||
static InvertMatrixFunction fn;
|
||||
builder.set_matching_fn(fn);
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ static void node_declare(NodeDeclarationBuilder &b)
|
|||
b.add_output<decl::Geometry>("Points").propagate_all();
|
||||
b.add_output<decl::Vector>("Tangent").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)
|
||||
|
@ -76,12 +76,12 @@ static void node_update(bNodeTree *ntree, bNode *node)
|
|||
|
||||
static void fill_rotation_attribute(const Span<float3> tangents,
|
||||
const Span<float3> normals,
|
||||
MutableSpan<float3> rotations)
|
||||
MutableSpan<math::Quaternion> rotations)
|
||||
{
|
||||
threading::parallel_for(IndexRange(rotations.size()), 512, [&](IndexRange range) {
|
||||
for (const int i : range) {
|
||||
rotations[i] = float3(
|
||||
math::to_euler(math::from_orthonormal_axes<float4x4>(normals[i], tangents[i])));
|
||||
rotations[i] = math::to_quaternion(
|
||||
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();
|
||||
const VArraySpan tangents = *attributes.lookup<float3>(tangent_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>(
|
||||
rotation_id, AttrDomain::Point);
|
||||
SpanAttributeWriter<math::Quaternion> rotations =
|
||||
attributes.lookup_or_add_for_write_only_span<math::Quaternion>(rotation_id,
|
||||
AttrDomain::Point);
|
||||
fill_rotation_attribute(tangents, normals, rotations.span);
|
||||
rotations.finish();
|
||||
}
|
||||
|
|
|
@ -333,29 +333,10 @@ if(WITH_PYTHON_MODULE)
|
|||
else()
|
||||
add_executable(blender ${EXETYPE} ${SRC})
|
||||
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
|
||||
# to this, this is to ensure this will be the first code to run once the
|
||||
# blender binary has been loaded by the OS.
|
||||
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()
|
||||
if(WIN32)
|
||||
add_executable(blender-launcher WIN32
|
||||
|
|
Loading…
Reference in New Issue