Geometry Nodes: Avoid index lookup from index mask #109174

Merged
Hans Goudey merged 9 commits from mod_moder/blender:avoid_mask_lookup into main 2023-06-23 19:20:30 +02:00
65 changed files with 1328 additions and 1228 deletions
Showing only changes of commit a42bdd4dc7 - Show all commits

View File

@ -79,6 +79,7 @@ typedef hiprtError(thiprtSetFuncTable)(hiprtContext context,
hiprtFuncDataSet set);
typedef hiprtError(thiprtDestroyFuncTable)(hiprtContext context,
hiprtFuncTable funcTable);
typedef void(thiprtSetLogLevel)( hiprtLogLevel level );
/* Function declarations. */
extern thiprtCreateContext *hiprtCreateContext;
@ -94,6 +95,7 @@ extern thiprtGetSceneBuildTemporaryBufferSize *hiprtGetSceneBuildTemporaryBuffer
extern thiprtCreateFuncTable *hiprtCreateFuncTable;
extern thiprtSetFuncTable *hiprtSetFuncTable;
extern thiprtDestroyFuncTable *hiprtDestroyFuncTable;
extern thiprtSetLogLevel *hiprtSetLogLevel;
/* HIPEW API. */

View File

@ -41,6 +41,7 @@ thiprtGetSceneBuildTemporaryBufferSize *hiprtGetSceneBuildTemporaryBufferSize;
thiprtCreateFuncTable *hiprtCreateFuncTable;
thiprtSetFuncTable *hiprtSetFuncTable;
thiprtDestroyFuncTable *hiprtDestroyFuncTable;
thiprtSetLogLevel *hiprtSetLogLevel;
static void hipewHipRtExit(void)
{
@ -89,6 +90,7 @@ bool hiprtewInit()
HIPRT_LIBRARY_FIND(hiprtCreateFuncTable)
HIPRT_LIBRARY_FIND(hiprtSetFuncTable)
HIPRT_LIBRARY_FIND(hiprtDestroyFuncTable)
HIPRT_LIBRARY_FIND(hiprtSetLogLevel)
result = true;
#endif

View File

@ -96,6 +96,8 @@ HIPRTDevice::HIPRTDevice(const DeviceInfo &info, Stats &stats, Profiler &profile
set_error(string_printf("Failed to create HIPRT Function Table"));
return;
}
hiprtSetLogLevel(hiprtLogLevelNone);
}
HIPRTDevice::~HIPRTDevice()
@ -261,8 +263,7 @@ string HIPRTDevice::compile_kernel(const uint kernel_features, const char *name,
linker_options.append(" --offload-arch=").append(arch);
linker_options.append(" -fgpu-rdc --hip-link --cuda-device-only ");
string hiprt_ver(HIPRT_VERSION_STR);
string hiprt_bc;
hiprt_bc = hiprt_path + "\\hiprt" + hiprt_ver + "_amd_lib_win.bc";
string hiprt_bc = hiprt_path + "\\dist\\bin\\Release\\hiprt" + hiprt_ver + "_amd_lib_win.bc";
string linker_command = string_printf("clang++ %s \"%s\" %s -o \"%s\"",
linker_options.c_str(),

View File

@ -61,6 +61,8 @@ bool HIPRTDeviceQueue::enqueue(DeviceKernel kernel,
0),
"enqueue");
debug_enqueue_end();
return !(hiprt_device_->have_error());
}

View File

@ -46,11 +46,11 @@ ccl_device_intersect bool scene_intersect(KernelGlobals kg,
GET_TRAVERSAL_STACK()
if (visibility & PATH_RAY_SHADOW_OPAQUE) {
GET_TRAVERSAL_ANY_HIT(table_closest_intersect, 0)
GET_TRAVERSAL_ANY_HIT(table_closest_intersect, 0, ray->time)
hit = traversal.getNextHit();
}
else {
GET_TRAVERSAL_CLOSEST_HIT(table_closest_intersect, 0)
GET_TRAVERSAL_CLOSEST_HIT(table_closest_intersect, 0, ray->time)
hit = traversal.getNextHit();
}
if (hit.hasHit()) {
@ -157,13 +157,13 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals kg,
payload.in_state = state;
payload.max_hits = max_hits;
payload.visibility = visibility;
payload.prim_type = PRIMITIVE_TRIANGLE;
payload.prim_type = PRIMITIVE_NONE;
payload.ray_time = ray->time;
payload.num_hits = 0;
payload.r_num_recorded_hits = num_recorded_hits;
payload.r_throughput = throughput;
GET_TRAVERSAL_STACK()
GET_TRAVERSAL_ANY_HIT(table_shadow_intersect, 1)
GET_TRAVERSAL_ANY_HIT(table_shadow_intersect, 1, ray->time)
hiprtHit hit = traversal.getNextHit();
num_recorded_hits = payload.r_num_recorded_hits;
throughput = payload.r_throughput;
@ -201,7 +201,7 @@ ccl_device_intersect bool scene_intersect_volume(KernelGlobals kg,
GET_TRAVERSAL_STACK()
GET_TRAVERSAL_CLOSEST_HIT(table_volume_intersect, 3)
GET_TRAVERSAL_CLOSEST_HIT(table_volume_intersect, 3, ray->time)
hiprtHit hit = traversal.getNextHit();
// return hit.hasHit();
if (hit.hasHit()) {

View File

@ -53,7 +53,7 @@ struct LocalPayload {
# endif
# ifdef HIPRT_SHARED_STACK
# define GET_TRAVERSAL_ANY_HIT(FUNCTION_TABLE, RAY_TYPE) \
# define GET_TRAVERSAL_ANY_HIT(FUNCTION_TABLE, RAY_TYPE, RAY_TIME) \
hiprtSceneTraversalAnyHitCustomStack<Stack> traversal(kernel_data.device_bvh, \
ray_hip, \
stack, \
@ -61,10 +61,10 @@ struct LocalPayload {
hiprtTraversalHintDefault, \
&payload, \
kernel_params.FUNCTION_TABLE, \
RAY_TYPE); \
hiprtSceneTraversalAnyHitCustomStack<Stack> traversal_simple( \
kernel_data.device_bvh, ray_hip, stack, visibility);
# define GET_TRAVERSAL_CLOSEST_HIT(FUNCTION_TABLE, RAY_TYPE) \
RAY_TYPE, \
RAY_TIME);
# define GET_TRAVERSAL_CLOSEST_HIT(FUNCTION_TABLE, RAY_TYPE, RAY_TIME) \
hiprtSceneTraversalClosestCustomStack<Stack> traversal(kernel_data.device_bvh, \
ray_hip, \
stack, \
@ -72,9 +72,8 @@ struct LocalPayload {
hiprtTraversalHintDefault, \
&payload, \
kernel_params.FUNCTION_TABLE, \
RAY_TYPE); \
hiprtSceneTraversalClosestCustomStack<Stack> traversal_simple( \
kernel_data.device_bvh, ray_hip, stack, visibility);
RAY_TYPE, \
RAY_TIME);
# else
# define GET_TRAVERSAL_ANY_HIT(FUNCTION_TABLE) \
hiprtSceneTraversalAnyHit traversal(kernel_data.device_bvh, \
@ -82,16 +81,14 @@ struct LocalPayload {
visibility, \
FUNCTION_TABLE, \
hiprtTraversalHintDefault, \
&payload); \
hiprtSceneTraversalAnyHit traversal_simple(kernel_data.device_bvh, ray_hip, visibility);
&payload);
# define GET_TRAVERSAL_CLOSEST_HIT(FUNCTION_TABLE) \
hiprtSceneTraversalClosest traversal(kernel_data.device_bvh, \
ray_hip, \
visibility, \
FUNCTION_TABLE, \
hiprtTraversalHintDefault, \
&payload); \
hiprtSceneTraversalClosest traversal_simple(kernel_data.device_bvh, ray_hip, visibility);
&payload);
# endif
ccl_device_inline void set_intersect_point(KernelGlobals kg,

View File

@ -2217,7 +2217,9 @@ def km_animation_channels(params):
items.extend([
# Click select.
("anim.channels_click", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
("anim.channels_click", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
("anim.channels_click", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True},
{"properties": [("extend_range", True)]}),
("anim.channels_click", {"type": 'LEFTMOUSE', "value": 'CLICK', "ctrl": True},
{"properties": [("extend", True)]}),
("anim.channels_click", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True},
{"properties": [("children_only", True)]}),

View File

@ -206,7 +206,7 @@ typedef struct GlyphBLF {
/**
* X and Y bearing of the glyph.
* The X bearing is from the origin to the glyph left bbox edge.
* The X bearing is from the origin to the glyph left bounding-box edge.
* The Y bearing is from the baseline to the top of the glyph edge.
*/
int pos[2];

View File

@ -930,7 +930,7 @@ void gather_attributes(AttributeAccessor src_attributes,
MutableAttributeAccessor dst_attributes);
/**
* Copy attribute values from groups groups defined by \a src_offsets to groups defined by \a
* Copy attribute values from groups defined by \a src_offsets to groups defined by \a
* dst_offsets. The group indices are gathered to the result by \a selection. The size of each
* source and result group must be the same.
*/

View File

@ -71,8 +71,7 @@ class Layer;
/**
* A TreeNode represents one node in the layer tree.
* It can either be a layer or a group. The node has zero children if it is a layer or zero or
more
* children if it is a group.
* more children if it is a group.
*/
class TreeNode : public ::GreasePencilLayerTreeNode {
public:

View File

@ -93,13 +93,15 @@ void normals_calc_poly_vert(Span<float3> vert_positions,
* a regular #float3 format.
*/
struct CornerNormalSpace {
/** Reference vector, orthogonal to corner normal. */
/** The automatically computed face corner normal, not including influence of custom normals. */
float3 vec_lnor;
/** Reference vector, orthogonal to #vec_lnor. */
float3 vec_ref;
/** Third vector, orthogonal to corner normal and #vec_ref. */
/** Third vector, orthogonal to #vec_lnor and #vec_ref. */
float3 vec_ortho;
/** Reference angle around #vec_ortho, in [0, pi] range (0.0 marks space as invalid). */
float ref_alpha;
/** Reference angle around corner normal, in [0, 2pi] range (0.0 marks space as invalid). */
/** Reference angle around #vec_lnor, in [0, 2pi] range (0.0 marks space as invalid). */
float ref_beta;
};
@ -131,7 +133,6 @@ struct CornerNormalSpaceArray {
};
void lnor_space_custom_normal_to_data(const CornerNormalSpace *lnor_space,
float3 lnor_no_custom,
const float custom_lnor[3],
short r_clnor_data[2]);

View File

@ -219,11 +219,13 @@ static void setup_app_userdef(BlendFileData *bfd)
}
}
/** Helper struct to manage IDs that are re-used across blendfile loading (i.e. moved from the old
* Main the the new one).
/**
* Helper struct to manage IDs that are re-used across blend-file loading (i.e. moved from the old
* Main the new one).
*
* NOTE: this is only used when actually loading a real .blend file, loading of memfile undo steps
* does not need it. */
* NOTE: this is only used when actually loading a real `.blend` file,
* loading of memfile undo steps does not need it.
*/
typedef struct ReuseOldBMainData {
Main *new_bmain;
Main *old_bmain;

View File

@ -432,15 +432,12 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
mirrorj += result_polys[mirror_i].size() - (j - src_poly.start());
}
const blender::float3 orig_normal = loop_normals[mirrorj];
copy_v3_v3(loop_normals[mirrorj], loop_normals[j]);
mul_m4_v3(mtx_nor, loop_normals[mirrorj]);
const int space_index = lnors_spacearr.corner_space_indices[mirrorj];
blender::bke::mesh::lnor_space_custom_normal_to_data(&lnors_spacearr.spaces[space_index],
orig_normal,
loop_normals[mirrorj],
clnors[mirrorj]);
blender::bke::mesh::lnor_space_custom_normal_to_data(
&lnors_spacearr.spaces[space_index], loop_normals[mirrorj], clnors[mirrorj]);
}
}
}

View File

@ -472,6 +472,8 @@ static void lnor_space_define(CornerNormalSpace *lnor_space,
return;
}
lnor_space->vec_lnor = lnor;
/* Compute ref alpha, average angle of all available edge vectors to lnor. */
if (!edge_vectors.is_empty()) {
float alpha = 0.0f;
@ -526,7 +528,7 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
using namespace blender::bke::mesh;
CornerNormalSpace space{};
lnor_space_define(&space, lnor, vec_ref, vec_other, edge_vectors);
copy_v3_v3(lnor_space->vec_lnor, lnor);
copy_v3_v3(lnor_space->vec_lnor, space.vec_lnor);
copy_v3_v3(lnor_space->vec_ref, space.vec_ref);
copy_v3_v3(lnor_space->vec_ortho, space.vec_ortho);
lnor_space->ref_alpha = space.ref_alpha;
@ -570,13 +572,12 @@ MINLINE short unit_float_to_short(const float val)
namespace blender::bke::mesh {
static void lnor_space_custom_data_to_normal(const CornerNormalSpace *lnor_space,
const float3 lnor_no_custom,
const short clnor_data[2],
float r_custom_lnor[3])
{
/* NOP custom normal data or invalid lnor space, return. */
if (clnor_data[0] == 0 || lnor_space->ref_alpha == 0.0f || lnor_space->ref_beta == 0.0f) {
copy_v3_v3(r_custom_lnor, lnor_no_custom);
copy_v3_v3(r_custom_lnor, lnor_space->vec_lnor);
return;
}
@ -589,7 +590,7 @@ static void lnor_space_custom_data_to_normal(const CornerNormalSpace *lnor_space
alphafac;
const float betafac = unit_short_to_float(clnor_data[1]);
mul_v3_v3fl(r_custom_lnor, lnor_no_custom, cosf(alpha));
mul_v3_v3fl(r_custom_lnor, lnor_space->vec_lnor, cosf(alpha));
if (betafac == 0.0f) {
madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinf(alpha));
@ -611,29 +612,29 @@ void BKE_lnor_space_custom_data_to_normal(const MLoopNorSpace *lnor_space,
{
using namespace blender::bke::mesh;
CornerNormalSpace space;
space.vec_lnor = lnor_space->vec_lnor;
space.vec_ref = lnor_space->vec_ref;
space.vec_ortho = lnor_space->vec_ortho;
space.ref_alpha = lnor_space->ref_alpha;
space.ref_beta = lnor_space->ref_beta;
lnor_space_custom_data_to_normal(&space, lnor_space->vec_lnor, clnor_data, r_custom_lnor);
lnor_space_custom_data_to_normal(&space, clnor_data, r_custom_lnor);
}
namespace blender::bke::mesh {
void lnor_space_custom_normal_to_data(const CornerNormalSpace *lnor_space,
const float3 lnor_no_custom,
const float custom_lnor[3],
short r_clnor_data[2])
{
/* We use nullptr vector as NOP custom normal (can be simpler than giving auto-computed `lnor`).
*/
if (is_zero_v3(custom_lnor) || compare_v3v3(lnor_no_custom, custom_lnor, 1e-4f)) {
if (is_zero_v3(custom_lnor) || compare_v3v3(lnor_space->vec_lnor, custom_lnor, 1e-4f)) {
r_clnor_data[0] = r_clnor_data[1] = 0;
return;
}
{
const float pi2 = float(M_PI * 2.0);
const float cos_alpha = dot_v3v3(lnor_no_custom, custom_lnor);
const float cos_alpha = dot_v3v3(lnor_space->vec_lnor, custom_lnor);
float vec[3], cos_beta;
float alpha;
@ -648,7 +649,7 @@ void lnor_space_custom_normal_to_data(const CornerNormalSpace *lnor_space,
}
/* Project custom lnor on (vec_ref, vec_ortho) plane. */
mul_v3_v3fl(vec, lnor_no_custom, -cos_alpha);
mul_v3_v3fl(vec, lnor_space->vec_lnor, -cos_alpha);
add_v3_v3(vec, custom_lnor);
normalize_v3(vec);
@ -680,11 +681,12 @@ void BKE_lnor_space_custom_normal_to_data(const MLoopNorSpace *lnor_space,
{
using namespace blender::bke::mesh;
CornerNormalSpace space;
space.vec_lnor = lnor_space->vec_lnor;
space.vec_ref = lnor_space->vec_ref;
space.vec_ortho = lnor_space->vec_ortho;
space.ref_alpha = lnor_space->ref_alpha;
space.ref_beta = lnor_space->ref_beta;
lnor_space_custom_normal_to_data(&space, lnor_space->vec_lnor, custom_lnor, r_clnor_data);
lnor_space_custom_normal_to_data(&space, custom_lnor, r_clnor_data);
}
namespace blender::bke::mesh {
@ -901,10 +903,8 @@ static void lnor_space_for_single_fan(LoopSplitTaskDataCommon *common_data,
lnors_spacearr->corner_space_indices[ml_curr_index] = space_index;
if (!clnors_data.is_empty()) {
lnor_space_custom_data_to_normal(lnor_space,
loop_normals[ml_curr_index],
clnors_data[ml_curr_index],
loop_normals[ml_curr_index]);
lnor_space_custom_data_to_normal(
lnor_space, clnors_data[ml_curr_index], loop_normals[ml_curr_index]);
}
if (!lnors_spacearr->corners_by_space.is_empty()) {
@ -1084,7 +1084,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data,
/* Extra bonus: since small-stack is local to this function,
* no more need to empty it at all cost! */
lnor_space_custom_data_to_normal(lnor_space, lnor, *clnor_ref, lnor);
lnor_space_custom_data_to_normal(lnor_space, *clnor_ref, lnor);
}
}
@ -1600,8 +1600,7 @@ static void mesh_normals_loop_custom_set(Span<float3> positions,
float *nor = r_custom_loop_normals[nidx];
const int space_index = lnors_spacearr.corner_space_indices[i];
lnor_space_custom_normal_to_data(
&lnors_spacearr.spaces[space_index], loop_normals[i], nor, r_clnors_data[i]);
lnor_space_custom_normal_to_data(&lnors_spacearr.spaces[space_index], nor, r_clnors_data[i]);
done_loops[i].reset();
}
else {
@ -1618,7 +1617,7 @@ static void mesh_normals_loop_custom_set(Span<float3> positions,
mul_v3_fl(avg_nor, 1.0f / float(fan_corners.size()));
short2 clnor_data_tmp;
lnor_space_custom_normal_to_data(
&lnors_spacearr.spaces[space_index], loop_normals[i], avg_nor, clnor_data_tmp);
&lnors_spacearr.spaces[space_index], avg_nor, clnor_data_tmp);
r_clnors_data.fill_indices(fan_corners, clnor_data_tmp);
}

View File

@ -746,6 +746,15 @@ template<typename T> class MutableSpan {
return counter;
}
/**
* Does a constant time check to see if the pointer points to a value in the referenced array.
* Return true if it is, otherwise false.
*/
constexpr bool contains_ptr(const T *ptr) const
{
return (this->begin() <= ptr) && (ptr < this->end());
}
/**
* Copy all values from another span into this span. This invokes undefined behavior when the
* destination contains uninitialized data and T is not trivially copy constructible.

View File

@ -1086,9 +1086,8 @@ uint BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const float n
for (a = 0; a < poly; a++, pf++) {
for (c = (ushort)(a + 1); c < poly; c++) {
/* if 'a' inside 'c': join (bbox too)
* Careful: 'a' can also be inside another poly.
*/
/* If 'a' inside 'c': join (bounding-box too)
* Careful: 'a' can also be inside another poly. */
if (boundisect(pf, pflist + c)) {
*pc = c;
pc++;

View File

@ -519,13 +519,13 @@ static void do_versions_nodetree_customnodes(bNodeTree *ntree, int UNUSED(is_gro
/* tree type idname */
switch (ntree->type) {
case NTREE_COMPOSIT:
strcpy(ntree->idname, "CompositorNodeTree");
STRNCPY(ntree->idname, "CompositorNodeTree");
break;
case NTREE_SHADER:
strcpy(ntree->idname, "ShaderNodeTree");
STRNCPY(ntree->idname, "ShaderNodeTree");
break;
case NTREE_TEXTURE:
strcpy(ntree->idname, "TextureNodeTree");
STRNCPY(ntree->idname, "TextureNodeTree");
break;
}
@ -1732,13 +1732,13 @@ if (!MAIN_VERSION_ATLEAST(bmain, 266, 2)) {
/* convert deprecated treetype setting to tree_idname */
switch (snode->treetype) {
case NTREE_COMPOSIT:
strcpy(snode->tree_idname, "CompositorNodeTree");
STRNCPY(snode->tree_idname, "CompositorNodeTree");
break;
case NTREE_SHADER:
strcpy(snode->tree_idname, "ShaderNodeTree");
STRNCPY(snode->tree_idname, "ShaderNodeTree");
break;
case NTREE_TEXTURE:
strcpy(snode->tree_idname, "TextureNodeTree");
STRNCPY(snode->tree_idname, "TextureNodeTree");
break;
}
}

View File

@ -54,8 +54,8 @@
* - write #BLO_CODE_GLOB (#FileGlobal struct) (some global vars).
* - write #BLO_CODE_DNA1 (#SDNA struct)
* - write #BLO_CODE_USER (#UserDef struct) for file paths:
- #BLENDER_STARTUP_FILE (on UNIX `~/.config/blender/X.X/config/startup.blend`).
- #BLENDER_USERPREF_FILE (on UNIX `~/.config/blender/X.X/config/userpref.blend`).
* - #BLENDER_STARTUP_FILE (on UNIX `~/.config/blender/X.X/config/startup.blend`).
* - #BLENDER_USERPREF_FILE (on UNIX `~/.config/blender/X.X/config/userpref.blend`).
*/
#include <cerrno>

View File

@ -440,7 +440,7 @@ BMLoop *BM_edge_other_loop(BMEdge *e, BMLoop *l)
{
BMLoop *l_other;
// BLI_assert(BM_edge_is_manifold(e)); // TOO strict, just check if we have another radial face
// BLI_assert(BM_edge_is_manifold(e)); /* Too strict, just check there is another radial face. */
BLI_assert(e->l && e->l->radial_next != e->l);
BLI_assert(BM_vert_in_edge(e, l->v));

View File

@ -112,6 +112,7 @@ set(GLSL_SRC
shaders/compositor_blur_variable_size.glsl
shaders/compositor_bokeh_image.glsl
shaders/compositor_box_mask.glsl
shaders/compositor_compute_preview.glsl
shaders/compositor_convert.glsl
shaders/compositor_despeckle.glsl
shaders/compositor_directional_blur.glsl
@ -226,6 +227,7 @@ set(SRC_SHADER_CREATE_INFOS
shaders/infos/compositor_blur_variable_size_info.hh
shaders/infos/compositor_bokeh_image_info.hh
shaders/infos/compositor_box_mask_info.hh
shaders/infos/compositor_compute_preview_info.hh
shaders/infos/compositor_convert_info.hh
shaders/infos/compositor_despeckle_info.hh
shaders/infos/compositor_directional_blur_info.hh

View File

@ -42,6 +42,9 @@ class Context {
public:
Context(TexturePool &texture_pool);
/* Get the compositing scene. */
virtual const Scene &get_scene() const = 0;
/* Get the node tree used for compositing. */
virtual const bNodeTree &get_node_tree() const = 0;

View File

@ -12,6 +12,7 @@
#include "COM_context.hh"
#include "COM_operation.hh"
#include "COM_result.hh"
#include "COM_scheduler.hh"
namespace blender::realtime_compositor {
@ -44,6 +45,12 @@ class NodeOperation : public Operation {
void compute_results_reference_counts(const Schedule &schedule);
protected:
/* Compute a preview for the operation and set to the bNodePreview of the node. This is only done
* for nodes which enables previews, are not hidden, and are part of the active node context. The
* preview is computed as a lower resolution version of the output of the get_preview_result
* method. */
void compute_preview() override;
/* Returns a reference to the derived node that this operation represents. */
const DNode &node() const;
@ -53,6 +60,17 @@ class NodeOperation : public Operation {
/* Returns true if the output identified by the given identifier is needed and should be
* computed, otherwise returns false. */
bool should_compute_output(StringRef identifier);
private:
/* Get the result which will be previewed in the node, this is chosen as the first linked output
* of the node, if no outputs exist, then the first allocated input will be chosen. Nullptr is
* guaranteed not to be returned, since the node will always either have a linked output or an
* allocated input. */
Result *get_preview_result();
/* Resize the give input result to the given preview size and set it to the preview buffer after
* applying the necessary color management processor.*/
void write_preview_from_result(bNodePreview &preview, Result &input_result);
};
} // namespace blender::realtime_compositor

View File

@ -130,6 +130,10 @@ class Operation {
* output results. */
virtual void execute() = 0;
/* Compute and set a preview of the operation if needed. This method defaults to an empty
* implementation and should be implemented by operations which can have previews. */
virtual void compute_preview();
/* Get a reference to the result connected to the input identified by the given identifier. */
Result &get_input(StringRef identifier) const;

View File

@ -4,15 +4,29 @@
#include <memory>
#include "BLI_assert.h"
#include "BLI_index_range.hh"
#include "BLI_map.hh"
#include "BLI_math_base.h"
#include "BLI_math_base.hh"
#include "BLI_math_color.h"
#include "BLI_math_vector_types.hh"
#include "BLI_string_ref.hh"
#include "BLI_task.hh"
#include "BLI_vector.hh"
#include "GPU_shader.h"
#include "GPU_texture.h"
#include "IMB_colormanagement.h"
#include "DNA_node_types.h"
#include "NOD_derived_node_tree.hh"
#include "NOD_node_declaration.hh"
#include "BKE_node.h"
#include "COM_context.hh"
#include "COM_input_descriptor.hh"
#include "COM_node_operation.hh"
@ -39,6 +53,126 @@ NodeOperation::NodeOperation(Context &context, DNode node) : Operation(context),
}
}
/* Given the size of a result, compute a lower resolution size for a preview. The greater dimension
* will be assigned an arbitrarily chosen size of 128, while the other dimension will get the size
* that maintains the same aspect ratio. */
static int2 compute_preview_size(int2 size)
{
const int greater_dimension_size = 128;
if (size.x > size.y) {
return int2(greater_dimension_size, int(greater_dimension_size * (float(size.y) / size.x)));
}
else {
return int2(int(greater_dimension_size * (float(size.x) / size.y)), greater_dimension_size);
}
}
void NodeOperation::compute_preview()
{
if (!(node()->flag & NODE_PREVIEW)) {
return;
}
if (node()->flag & NODE_HIDDEN) {
return;
}
/* Only compute previews for nodes in the active context. */
if (node().context()->instance_key().value !=
node().context()->derived_tree().active_context().instance_key().value)
{
return;
}
/* Initialize node tree previews if not already initialized. */
bNodeTree *root_tree = const_cast<bNodeTree *>(
&node().context()->derived_tree().root_context().btree());
if (!root_tree->previews) {
root_tree->previews = BKE_node_instance_hash_new("node previews");
}
Result *preview_result = get_preview_result();
const int2 preview_size = compute_preview_size(preview_result->domain().size);
node()->runtime->preview_xsize = preview_size.x;
node()->runtime->preview_ysize = preview_size.y;
bNodePreview *preview = bke::node_preview_verify(
root_tree->previews, node().instance_key(), preview_size.x, preview_size.y, true);
write_preview_from_result(*preview, *preview_result);
}
Result *NodeOperation::get_preview_result()
{
/* Find the first linked output. */
for (const bNodeSocket *output : node()->output_sockets()) {
Result &output_result = get_result(output->identifier);
if (output_result.should_compute()) {
return &output_result;
}
}
/* No linked outputs, find the first allocated input. */
for (const bNodeSocket *input : node()->input_sockets()) {
Result &input_result = get_input(input->identifier);
if (input_result.is_allocated()) {
return &input_result;
}
}
BLI_assert_unreachable();
return nullptr;
}
void NodeOperation::write_preview_from_result(bNodePreview &preview, Result &input_result)
{
GPUShader *shader = shader_manager().get("compositor_compute_preview");
GPU_shader_bind(shader);
if (input_result.type() == ResultType::Float) {
GPU_texture_swizzle_set(input_result.texture(), "rrr1");
}
input_result.bind_as_texture(shader, "input_tx");
const int2 preview_size = int2(preview.xsize, preview.ysize);
Result preview_result = Result::Temporary(ResultType::Color, texture_pool());
preview_result.allocate_texture(Domain(preview_size));
preview_result.bind_as_image(shader, "preview_img");
compute_dispatch_threads_at_least(shader, preview_size);
input_result.unbind_as_texture();
preview_result.unbind_as_image();
GPU_shader_unbind();
GPU_memory_barrier(GPU_BARRIER_TEXTURE_FETCH);
float *preview_pixels = static_cast<float *>(
GPU_texture_read(preview_result.texture(), GPU_DATA_FLOAT, 0));
preview_result.release();
ColormanageProcessor *color_processor = IMB_colormanagement_display_processor_new(
&context().get_scene().view_settings, &context().get_scene().display_settings);
threading::parallel_for(IndexRange(preview_size.y), 1, [&](const IndexRange sub_y_range) {
for (const int64_t y : sub_y_range) {
for (const int64_t x : IndexRange(preview_size.x)) {
const int index = (y * preview_size.x + x) * 4;
IMB_colormanagement_processor_apply_v4(color_processor, preview_pixels + index);
rgba_float_to_uchar(preview.rect + index, preview_pixels + index);
}
}
});
/* Restore original swizzle mask set above. */
if (input_result.type() == ResultType::Float) {
GPU_texture_swizzle_set(input_result.texture(), "rgba");
}
IMB_colormanagement_processor_free(color_processor);
MEM_freeN(preview_pixels);
}
void NodeOperation::compute_results_reference_counts(const Schedule &schedule)
{
for (const bNodeSocket *output : this->node()->output_sockets()) {

View File

@ -35,6 +35,8 @@ void Operation::evaluate()
execute();
compute_preview();
release_inputs();
release_unneeded_results();
@ -136,6 +138,8 @@ void Operation::add_and_evaluate_input_processor(StringRef identifier, SimpleOpe
processor->evaluate();
}
void Operation::compute_preview(){};
Result &Operation::get_input(StringRef identifier) const
{
return *results_mapped_to_inputs_.lookup(identifier);

View File

@ -21,58 +21,6 @@ namespace blender::realtime_compositor {
using namespace nodes::derived_node_tree_types;
/* Find the active context from the given context and its descendants contexts. The active context
* is the one whose node instance key matches the active_viewer_key stored in the root node tree.
* The instance key of each context is computed by calling BKE_node_instance_key given the key of
* the parent as well as the group node making the context. */
static const DTreeContext *find_active_context_recursive(const DTreeContext *context,
bNodeInstanceKey key)
{
/* The instance key of the given context matches the active viewer instance key, so this is the
* active context, return it. */
if (key.value == context->derived_tree().root_context().btree().active_viewer_key.value) {
return context;
}
/* For each of the group nodes, compute their instance key and contexts and call this function
* recursively. */
for (const bNode *group_node : context->btree().group_nodes()) {
const bNodeInstanceKey child_key = BKE_node_instance_key(key, &context->btree(), group_node);
const DTreeContext *child_context = context->child_context(*group_node);
const DTreeContext *found_context = find_active_context_recursive(child_context, child_key);
/* If the found context is null, that means neither the child context nor one of its descendant
* contexts is active. */
if (!found_context) {
continue;
}
/* Otherwise, we have found our active context, return it. */
return found_context;
}
/* Neither the given context nor one of its descendant contexts is active, so return null. */
return nullptr;
}
/* Find the active context for the given node tree. The active context represents the node tree
* currently being edited. In most cases, that would be the top level node tree itself, but in the
* case where the user is editing the node tree of a node group, the active context would be a
* representation of the node tree of that node group. Note that the context also stores the group
* node that the user selected to edit the node tree, so the context fully represents a particular
* instance of the node group. */
static const DTreeContext *find_active_context(const DerivedNodeTree &tree)
{
/* If the active viewer key is NODE_INSTANCE_KEY_NONE, that means it is not yet initialized and
* we return the root context in that case. See the find_active_context_recursive function. */
if (tree.root_context().btree().active_viewer_key.value == NODE_INSTANCE_KEY_NONE.value) {
return &tree.root_context();
}
/* The root context has an instance key of NODE_INSTANCE_KEY_BASE by definition. */
return find_active_context_recursive(&tree.root_context(), NODE_INSTANCE_KEY_BASE);
}
/* Add the viewer node which is marked as NODE_DO_OUTPUT in the given context to the given stack.
* If multiple types of viewer nodes are marked, then the preference will be CMP_NODE_VIEWER >
* CMP_NODE_SPLITVIEWER. If no viewer nodes were found, composite nodes can be added as a fallback
@ -114,7 +62,8 @@ static bool add_viewer_nodes_in_context(const DTreeContext *context, Stack<DNode
* Output, Composite, and Viewer nodes. Viewer nodes are a special case, as only the nodes that
* satisfies the requirements in the add_viewer_nodes_in_context function are added. First, the
* active context is searched for viewer nodes, if non were found, the root context is searched.
* For more information on what contexts mean here, see the find_active_context function. */
* For more information on what contexts mean here, see the DerivedNodeTree::active_context()
* function. */
static void add_output_nodes(const Context &context,
const DerivedNodeTree &tree,
Stack<DNode> &node_stack)
@ -139,8 +88,8 @@ static void add_output_nodes(const Context &context,
}
}
const DTreeContext *active_context = find_active_context(tree);
const bool viewer_was_added = add_viewer_nodes_in_context(active_context, node_stack);
const DTreeContext &active_context = tree.active_context();
const bool viewer_was_added = add_viewer_nodes_in_context(&active_context, node_stack);
/* An active viewer was added, no need to search further. */
if (viewer_was_added) {
@ -149,7 +98,7 @@ static void add_output_nodes(const Context &context,
/* If the active context is the root one and no viewer nodes were found, we consider this node
* tree to have no viewer nodes, even if one of the non-active descendants have viewer nodes. */
if (active_context->is_root()) {
if (active_context.is_root()) {
return;
}
@ -394,7 +343,8 @@ Schedule compute_schedule(const Context &context, const DerivedNodeTree &tree)
int insertion_position = 0;
for (int i = 0; i < sorted_dependency_nodes.size(); i++) {
if (needed_buffers.lookup(doutput.node()) >
needed_buffers.lookup(sorted_dependency_nodes[i])) {
needed_buffers.lookup(sorted_dependency_nodes[i]))
{
insertion_position++;
}
else {

View File

@ -0,0 +1,6 @@
void main()
{
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
vec2 coordinates = (vec2(texel) + vec2(0.5)) / vec2(imageSize(preview_img));
imageStore(preview_img, texel, texture(input_tx, coordinates));
}

View File

@ -0,0 +1,12 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_create_info.hh"
GPU_SHADER_CREATE_INFO(compositor_compute_preview)
.local_group_size(16, 16)
.sampler(0, ImageType::FLOAT_2D, "input_tx")
.image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "preview_img")
.compute_source("compositor_compute_preview.glsl")
.do_static_compilation(true);

View File

@ -34,7 +34,7 @@ void ObjectRuntimeBackup::init_from_object(Object *object)
light_linking_runtime = object->light_linking->runtime;
}
BKE_object_runtime_reset(object);
/* Keep bbox (for now at least). */
/* Keep bounding-box (for now at least). */
object->runtime.bb = runtime.bb;
/* Object update will override actual object->data to an evaluated version.
* Need to make sure we don't have data set to evaluated one before free

View File

@ -58,6 +58,11 @@ class Context : public realtime_compositor::Context {
{
}
const Scene &get_scene() const override
{
return *DRW_context_state_get()->scene;
}
const bNodeTree &get_node_tree() const override
{
return *DRW_context_state_get()->scene->nodetree;

View File

@ -10,6 +10,8 @@
#include "DNA_scene_types.h"
//#define DEBUG_SNAP_TIME
#ifdef __cplusplus
extern "C" {
#endif
@ -194,6 +196,12 @@ bool ED_transform_snap_object_project_all_view3d_ex(SnapObjectContext *sctx,
bool sort,
ListBase *r_hit_list);
#ifdef DEBUG_SNAP_TIME
void ED_transform_snap_object_time_average_print(void);
#else
# define ED_transform_snap_object_time_average_print() void(0)
#endif
#ifdef __cplusplus
}
#endif

View File

@ -3291,7 +3291,7 @@ static void do_vpaint_brush_smear(bContext *C,
/* if the vertex is selected for painting. */
if (!use_vert_sel || select_vert[v_index]) {
/* Calc the dot prod. between ray norm on surf and current vert
/* Calculate the dot prod. between ray norm on surf and current vert
* (ie splash prevention factor), and only paint front facing verts. */
float brush_strength = cache->bstrength;
const float angle_cos = (use_normal && vd.no) ?

View File

@ -6402,7 +6402,7 @@ void SCULPT_topology_islands_ensure(Object *ob)
*static_cast<uint8_t *>(
SCULPT_vertex_attr_get(vertex2, ss->attrs.topology_island_key)) = island_nr;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex2, ni) {
SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, vertex2, ni) {
if (visit.add(ni.vertex) && SCULPT_vertex_any_face_visible_get(ss, ni.vertex)) {
stack.append(ni.vertex);
}

View File

@ -988,34 +988,39 @@ void fsmenu_read_system(FSMenu *fsmenu, int read_bookmarks)
fprintf(stderr, "could not close the list of mounted file-systems\n");
}
}
/* Check gvfs shares. */
/* Check `gvfs` shares. */
const char *const xdg_runtime_dir = BLI_getenv("XDG_RUNTIME_DIR");
if (xdg_runtime_dir != NULL) {
struct direntry *dirs;
char filepath[FILE_MAX];
BLI_path_join(filepath, sizeof(filepath), xdg_runtime_dir, "gvfs/");
const uint dirs_num = BLI_filelist_dir_contents(filepath, &dirs);
for (uint i = 0; i < dirs_num; i++) {
if (dirs[i].type & S_IFDIR) {
const char *dirname = dirs[i].relname;
if (dirname[0] != '.') {
/* Dir names contain a lot of unwanted text.
* Assuming every entry ends with the share name */
const char *label = strstr(dirname, "share=");
if (label != NULL) {
/* Move pointer so "share=" is trimmed off
* or use full dirname as label. */
const char *label_test = label + 6;
label = *label_test ? label_test : dirname;
}
SNPRINTF(line, "%s%s", filepath, dirname);
fsmenu_insert_entry(
fsmenu, FS_CATEGORY_SYSTEM, line, label, ICON_NETWORK_DRIVE, FS_INSERT_SORTED);
found = 1;
/* Avoid error message if the directory doesn't exist as this isn't a requirement. */
if (BLI_is_dir(filepath)) {
const uint dirs_num = BLI_filelist_dir_contents(filepath, &dirs);
for (uint i = 0; i < dirs_num; i++) {
if ((dirs[i].type & S_IFDIR) == 0) {
continue;
}
const char *dirname = dirs[i].relname;
if (dirname[0] == '.') {
continue;
}
/* Directory names contain a lot of unwanted text.
* Assuming every entry ends with the share name. */
const char *label = strstr(dirname, "share=");
if (label != NULL) {
/* Move pointer so `share=` is trimmed off or use full `dirname` as label. */
const char *label_test = label + 6;
label = *label_test ? label_test : dirname;
}
SNPRINTF(line, "%s%s", filepath, dirname);
fsmenu_insert_entry(
fsmenu, FS_CATEGORY_SYSTEM, line, label, ICON_NETWORK_DRIVE, FS_INSERT_SORTED);
found = 1;
}
BLI_filelist_free(dirs, dirs_num);
}
BLI_filelist_free(dirs, dirs_num);
}
# endif

View File

@ -688,9 +688,9 @@ static void nla_draw_strip_frames_text(
/* Always draw times above the strip, whereas sequencer drew below + above.
* However, we should be fine having everything on top, since these tend to be
* quite spaced out.
* - 1 dp is compromise between lack of precision (ints only, as per sequencer)
* while also preserving some accuracy, since we do use floats
*/
* NOTE: 1 decimal point is a compromise between lack of precision (ints only, as per sequencer)
* while also preserving some accuracy, since we do use floats. */
/* start frame */
numstr_len = SNPRINTF_RLEN(numstr, "%.1f", strip->start);
UI_view2d_text_cache_add(v2d, strip->start - 1.0f, ymaxc + ytol, numstr, numstr_len, col);

View File

@ -56,8 +56,10 @@ typedef struct TransDataNla {
/** index of track that strip is currently in. */
int trackIndex;
/** NOTE: This index is relative to the initial first track at the start of transforming and
* thus can be negative when the tracks list grows downward. */
/**
* \note This index is relative to the initial first track at the start of transforming and
* thus can be negative when the tracks list grows downward.
*/
int signed_track_index;
/** handle-index: 0 for dummy entry, -1 for start, 1 for end, 2 for both ends. */
@ -125,8 +127,8 @@ static float transdata_get_time_shuffle_offset_side(ListBase *trans_datas, const
total_offset += offset;
} while (!IS_EQT(offset, 0.0f, 1e-4));
/* Needs a eps greater than FLT_EPS because strip->start/end could be non-integral, and after
* those calculations, `offset` could fall outside of FLT_EPS. */
/* Needs a epsilon greater than FLT_EPS because strip->start/end could be non-integral,
* and after those calculations, `offset` could fall outside of FLT_EPS. */
return total_offset;
}
@ -148,8 +150,8 @@ static float transdata_get_time_shuffle_offset(ListBase *trans_datas)
return -offset_left < offset_right ? offset_left : offset_right;
}
/** Assumes all of given trans_datas are part of the same ID.
*
/**
* Assumes all of given trans_datas are part of the same ID.
*
* \param shuffle_direction: the direction the strip is traveling. 1 is towards the bottom
* of the stack, -1 is away from it.
@ -205,7 +207,8 @@ static bool transdata_get_track_shuffle_offset_side(ListBase *trans_datas,
return true;
}
/** Assumes all of given trans_datas are part of the same ID.
/**
* Assumes all of given trans_datas are part of the same ID.
*
* \param r_track_offset: The minimal total signed offset that results in valid strip track-moves
* for all strips from \a trans_datas.
@ -243,7 +246,6 @@ static bool transdata_get_track_shuffle_offset(ListBase *trans_datas, int *r_tra
/** \name Transform application to NLA strips
* \{ */
/** \} */
static void nlatrack_truncate_temporary_tracks(bAnimContext *ac)
{
short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
@ -288,6 +290,9 @@ static void nlatrack_truncate_temporary_tracks(bAnimContext *ac)
ANIM_animdata_freelist(&anim_data);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Transform application to NLA strips
* \{ */
@ -744,8 +749,7 @@ static void recalcData_nla(TransInfo *t)
*
* Determine dst_track, which will end up being NULL, the last library override
* track, or a normal local track. The first two cases lead to delta_new_tracks!=0.
* The last case leads to delta_new_tracks==0.
*/
* The last case leads to `delta_new_tracks == 0`. */
int delta_new_tracks = delta;
/* it's possible to drag a strip fast enough to make delta > |1|. We only want to process
@ -760,14 +764,13 @@ static void recalcData_nla(TransInfo *t)
}
/* We assume all library tracks are grouped at the bottom of the nla stack.
* Thus, no need to check for them when moving tracks upward.
*/
* Thus, no need to check for them when moving tracks upward. */
while (delta_new_tracks > 0) {
dst_track = dst_track->next;
delta_new_tracks--;
}
for (int i = 0; i < -delta_new_tracks; i++) {
for (int j = 0; j < -delta_new_tracks; j++) {
NlaTrack *new_track = BKE_nlatrack_new();
new_track->flag |= NLATRACK_TEMPORARILY_ADDED;
BKE_nlatrack_insert_before(
@ -775,7 +778,7 @@ static void recalcData_nla(TransInfo *t)
dst_track = new_track;
}
for (int i = 0; i < delta_new_tracks; i++) {
for (int j = 0; j < delta_new_tracks; j++) {
NlaTrack *new_track = BKE_nlatrack_new();
new_track->flag |= NLATRACK_TEMPORARILY_ADDED;

View File

@ -912,6 +912,8 @@ void freeSnapping(TransInfo *t)
else if (t->tsnap.object_context) {
ED_transform_snap_object_context_destroy(t->tsnap.object_context);
t->tsnap.object_context = nullptr;
ED_transform_snap_object_time_average_print();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -29,7 +29,7 @@ struct SnapObjectContext {
struct {
Depsgraph *depsgraph;
const ARegion *region;
const RegionView3D *rv3d;
const View3D *v3d;
eSnapMode snap_to_flag;
@ -42,7 +42,6 @@ struct SnapObjectContext {
float init_co[3];
float curr_co[3];
float pmat[4][4]; /* perspective matrix */
float win_size[2]; /* win x and y */
float clip_plane[MAX_CLIPPLANE_LEN][4];
int clip_plane_len;
@ -50,7 +49,6 @@ struct SnapObjectContext {
/* read/write */
uint object_index;
bool is_persp;
bool has_occlusion_plane; /* Ignore plane of occlusion in curves. */
bool use_occlusion_test_edit;
} runtime;
@ -116,6 +114,26 @@ using Nearest2DCopyVertNoCallback = void (*)(const int index,
float r_no[3]);
struct Nearest2dUserData {
public:
/* Constructor. */
Nearest2dUserData(SnapObjectContext *sctx,
float dist_px_sq,
const blender::float4x4 &obmat = blender::float4x4::identity());
void clip_planes_get(SnapObjectContext *sctx,
const blender::float4x4 &obmat,
bool skip_occlusion_plane = false);
bool snap_boundbox(const blender::float3 &min, const blender::float3 &max);
bool snap_point(const blender::float3 &co, int index = -1);
bool snap_edge(const blender::float3 &va, const blender::float3 &vb, int edge_index = -1);
DistProjectedAABBPrecalc nearest_precalc;
blender::float4x4 pmat_local;
blender::Vector<blender::float4, MAX_CLIPPLANE_LEN> clip_planes;
Nearest2DGetVertCoCallback get_vert_co;
Nearest2DGetEdgeVertsCallback get_edge_verts_index;
Nearest2DGetTriVertsCallback get_tri_verts_index;
@ -138,6 +156,8 @@ struct Nearest2dUserData {
bool is_persp;
bool use_backface_culling;
BVHTreeNearest nearest_point;
};
/* transform_snap_object.cc */
@ -147,13 +167,6 @@ void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRay
bool raycast_tri_backface_culling_test(
const float dir[3], const float v0[3], const float v1[3], const float v2[3], float no[3]);
bool snap_bound_box_check_dist(const float min[3],
const float max[3],
const float lpmat[4][4],
const float win_size[2],
const float mval[2],
float dist_px_sq);
void cb_snap_vert(void *userdata,
int index,
const DistProjectedAABBPrecalc *precalc,
@ -172,13 +185,7 @@ bool nearest_world_tree(SnapObjectContext *sctx,
BVHTree *tree,
BVHTree_NearestPointCallback nearest_cb,
void *treedata,
const float (*obmat)[4],
const float init_co[3],
const float curr_co[3],
float *r_dist_sq,
float *r_loc,
float *r_no,
int *r_index);
const float (*obmat)[4]);
/* transform_snap_object_editmesh.cc */
@ -217,13 +224,9 @@ eSnapMode snap_polygon_editmesh(SnapObjectContext *sctx,
ID *id,
const float obmat[4][4],
eSnapMode snap_to_flag,
int polygon,
const float clip_planes_local[MAX_CLIPPLANE_LEN][4]);
int polygon);
void nearest2d_data_init_editmesh(struct BMEditMesh *em,
bool is_persp,
bool use_backface_culling,
struct Nearest2dUserData *r_nearest2d);
void nearest2d_data_init_editmesh(struct BMEditMesh *em, struct Nearest2dUserData *r_nearest2d);
/* transform_snap_object_mesh.cc */
@ -239,10 +242,6 @@ eSnapMode snap_polygon_mesh(SnapObjectContext *sctx,
ID *id,
const float obmat[4][4],
eSnapMode snap_to_flag,
int polygon,
const float clip_planes_local[MAX_CLIPPLANE_LEN][4]);
int polygon);
void nearest2d_data_init_mesh(const Mesh *mesh,
bool is_persp,
bool use_backface_culling,
Nearest2dUserData *r_nearest2d);
void nearest2d_data_init_mesh(const Mesh *mesh, Nearest2dUserData *r_nearest2d);

View File

@ -21,6 +21,8 @@
#include "transform_snap_object.hh"
using namespace blender;
/* -------------------------------------------------------------------- */
/** \name Snap Object Data
* \{ */
@ -270,14 +272,7 @@ static bool raycastEditMesh(SnapData_EditMesh *sod,
SnapObjectContext *sctx,
BMEditMesh *em,
const float obmat[4][4],
const uint ob_index,
/* read/write args */
float *ray_depth,
/* return args */
float r_loc[3],
float r_no[3],
int *r_index,
ListBase *r_hit_list)
const uint ob_index)
{
bool retval = false;
@ -295,7 +290,7 @@ static bool raycastEditMesh(SnapData_EditMesh *sod,
/* local scale in normal direction */
local_scale = normalize_v3(ray_normal_local);
local_depth = *ray_depth;
local_depth = sctx->ret.ray_depth_max;
if (local_depth != BVH_RAYCAST_DIST_MAX) {
local_depth *= local_scale;
}
@ -309,11 +304,10 @@ static bool raycastEditMesh(SnapData_EditMesh *sod,
return retval;
}
/* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with
* very far away ray_start values (as returned in case of ortho view3d), see #50486, #38358.
*/
/* We pass a temp ray_start, set from object's bounding-box, to avoid precision issues with
* very far away ray_start values (as returned in case of ortho view3d), see #50486, #38358. */
if (len_diff > 400.0f) {
len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
len_diff -= local_scale; /* make temp start point a bit away from bounding-box hit point. */
madd_v3_v3fl(ray_start_local, ray_normal_local, len_diff);
local_depth -= len_diff;
}
@ -326,7 +320,7 @@ static bool raycastEditMesh(SnapData_EditMesh *sod,
return retval;
}
if (r_hit_list) {
if (sctx->ret.hit_list) {
RayCastAll_Data data;
data.bvhdata = treedata;
@ -335,14 +329,14 @@ static bool raycastEditMesh(SnapData_EditMesh *sod,
data.len_diff = len_diff;
data.local_scale = local_scale;
data.ob_uuid = ob_index;
data.hit_list = r_hit_list;
data.hit_list = sctx->ret.hit_list;
void *hit_last_prev = data.hit_list->last;
BLI_bvhtree_ray_cast_all(treedata->tree,
ray_start_local,
ray_normal_local,
0.0f,
*ray_depth,
sctx->ret.ray_depth_max,
raycast_all_cb,
&data);
@ -365,26 +359,21 @@ static bool raycastEditMesh(SnapData_EditMesh *sod,
{
hit.dist += len_diff;
hit.dist /= local_scale;
if (hit.dist <= *ray_depth) {
*ray_depth = hit.dist;
copy_v3_v3(r_loc, hit.co);
if (hit.dist <= sctx->ret.ray_depth_max) {
copy_v3_v3(sctx->ret.loc, hit.co);
copy_v3_v3(sctx->ret.no, hit.no);
/* Back to world-space. */
mul_m4_v3(obmat, r_loc);
mul_m4_v3(obmat, sctx->ret.loc);
if (r_no) {
copy_v3_v3(r_no, hit.no);
mul_transposed_mat3_m4_v3(imat, r_no);
normalize_v3(r_no);
}
mul_transposed_mat3_m4_v3(imat, sctx->ret.no);
normalize_v3(sctx->ret.no);
sctx->ret.ray_depth_max = hit.dist;
em = sod->treedata_editmesh.em;
sctx->ret.index = BM_elem_index_get(em->looptris[hit.index][0]->f);
retval = true;
if (r_index) {
em = sod->treedata_editmesh.em;
*r_index = BM_elem_index_get(em->looptris[hit.index][0]->f);
}
}
}
}
@ -399,30 +388,14 @@ static bool raycastEditMesh(SnapData_EditMesh *sod,
static bool nearest_world_editmesh(SnapData_EditMesh *sod,
SnapObjectContext *sctx,
BMEditMesh *em,
const float (*obmat)[4],
const float init_co[3],
const float curr_co[3],
float *r_dist_sq,
float *r_loc,
float *r_no,
int *r_index)
const float (*obmat)[4])
{
BVHTreeFromEditMesh *treedata = snap_object_data_editmesh_treedata_get(sod, sctx, em);
if (treedata == nullptr) {
return false;
}
return nearest_world_tree(sctx,
treedata->tree,
treedata->nearest_callback,
treedata,
obmat,
init_co,
curr_co,
r_dist_sq,
r_loc,
r_no,
r_index);
return nearest_world_tree(sctx, treedata->tree, treedata->nearest_callback, treedata, obmat);
}
/** \} */
@ -452,10 +425,7 @@ static void cb_bedge_verts_get(const int index, const Nearest2dUserData *data, i
r_v_index[1] = BM_elem_index_get(eed->v2);
}
void nearest2d_data_init_editmesh(BMEditMesh *em,
bool is_persp,
bool use_backface_culling,
Nearest2dUserData *r_nearest2d)
void nearest2d_data_init_editmesh(BMEditMesh *em, Nearest2dUserData *r_nearest2d)
{
r_nearest2d->get_vert_co = cb_bvert_co_get;
r_nearest2d->get_edge_verts_index = cb_bedge_verts_get;
@ -464,9 +434,6 @@ void nearest2d_data_init_editmesh(BMEditMesh *em,
r_nearest2d->get_tri_edges_index = nullptr;
r_nearest2d->bm = em->bm;
r_nearest2d->is_persp = is_persp;
r_nearest2d->use_backface_culling = use_backface_culling;
}
/** \} */
@ -480,8 +447,7 @@ eSnapMode snap_polygon_editmesh(SnapObjectContext *sctx,
ID * /*id*/,
const float obmat[4][4],
eSnapMode snap_to_flag,
int polygon,
const float clip_planes_local[MAX_CLIPPLANE_LEN][4])
int polygon)
{
eSnapMode elem = SCE_SNAP_MODE_NONE;
@ -492,22 +458,14 @@ eSnapMode snap_polygon_editmesh(SnapObjectContext *sctx,
BMEditMesh *em = sod->treedata_editmesh.em;
float lpmat[4][4];
mul_m4_m4m4(lpmat, sctx->runtime.pmat, obmat);
DistProjectedAABBPrecalc neasrest_precalc;
dist_squared_to_projected_aabb_precalc(
&neasrest_precalc, lpmat, sctx->runtime.win_size, sctx->runtime.mval);
Nearest2dUserData nearest2d(sctx, sctx->ret.dist_px_sq, float4x4(obmat));
nearest2d.clip_planes_get(sctx, float4x4(obmat));
nearest2d_data_init_editmesh(em, &nearest2d);
BVHTreeNearest nearest{};
nearest.index = -1;
nearest.dist_sq = sctx->ret.dist_px_sq;
Nearest2dUserData nearest2d;
nearest2d_data_init_editmesh(
em, sctx->runtime.is_persp, sctx->runtime.params.use_backface_culling, &nearest2d);
BM_mesh_elem_table_ensure(em->bm, BM_FACE);
BMFace *f = BM_face_at_index(em->bm, polygon);
BMLoop *l_iter, *l_first;
@ -519,9 +477,9 @@ eSnapMode snap_polygon_editmesh(SnapObjectContext *sctx,
do {
cb_snap_edge(&nearest2d,
BM_elem_index_get(l_iter->e),
&neasrest_precalc,
clip_planes_local,
sctx->runtime.clip_plane_len,
&nearest2d.nearest_precalc,
reinterpret_cast<float(*)[4]>(nearest2d.clip_planes.data()),
nearest2d.clip_planes.size(),
&nearest);
} while ((l_iter = l_iter->next) != l_first);
}
@ -532,9 +490,9 @@ eSnapMode snap_polygon_editmesh(SnapObjectContext *sctx,
do {
cb_snap_vert(&nearest2d,
BM_elem_index_get(l_iter->v),
&neasrest_precalc,
clip_planes_local,
sctx->runtime.clip_plane_len,
&nearest2d.nearest_precalc,
reinterpret_cast<float(*)[4]>(nearest2d.clip_planes.data()),
nearest2d.clip_planes.size(),
&nearest);
} while ((l_iter = l_iter->next) != l_first);
}
@ -565,24 +523,14 @@ static eSnapMode snapEditMesh(SnapData_EditMesh *sod,
SnapObjectContext *sctx,
BMEditMesh *em,
const float obmat[4][4],
eSnapMode snap_to_flag,
/* read/write args */
float *dist_px_sq,
/* return args */
float r_loc[3],
float r_no[3],
int *r_index)
eSnapMode snap_to_flag)
{
BLI_assert(snap_to_flag != SCE_SNAP_MODE_FACE);
float lpmat[4][4];
mul_m4_m4m4(lpmat, sctx->runtime.pmat, obmat);
/* Test BoundBox */
Nearest2dUserData nearest2d(sctx, sctx->ret.dist_px_sq, float4x4(obmat));
/* Was BKE_boundbox_ray_hit_check, see: cf6ca226fa58. */
if (!snap_bound_box_check_dist(
sod->min, sod->max, lpmat, sctx->runtime.win_size, sctx->runtime.mval, *dist_px_sq))
{
if (!nearest2d.snap_boundbox(sod->min, sod->max)) {
return SCE_SNAP_MODE_NONE;
}
@ -646,34 +594,24 @@ static eSnapMode snapEditMesh(SnapData_EditMesh *sod,
}
}
Nearest2dUserData nearest2d;
nearest2d_data_init_editmesh(sod->treedata_editmesh.em,
sctx->runtime.is_persp,
sctx->runtime.params.use_backface_culling,
&nearest2d);
nearest2d.clip_planes_get(sctx, float4x4(obmat));
nearest2d_data_init_editmesh(em, &nearest2d);
BVHTreeNearest nearest{};
nearest.index = -1;
nearest.dist_sq = *dist_px_sq;
nearest.dist_sq = sctx->ret.dist_px_sq;
eSnapMode elem = SCE_SNAP_MODE_VERTEX;
float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
transpose_m4_m4(tobmat, obmat);
for (int i = sctx->runtime.clip_plane_len; i--;) {
mul_v4_m4v4(clip_planes_local[i], tobmat, sctx->runtime.clip_plane[i]);
}
if (sod->bvhtree[0] && (snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
BLI_bvhtree_find_nearest_projected(sod->bvhtree[0],
lpmat,
nearest2d.pmat_local.ptr(),
sctx->runtime.win_size,
sctx->runtime.mval,
clip_planes_local,
sctx->runtime.clip_plane_len,
reinterpret_cast<float(*)[4]>(nearest2d.clip_planes.data()),
nearest2d.clip_planes.size(),
&nearest,
cb_snap_vert,
&nearest2d);
@ -685,11 +623,11 @@ static eSnapMode snapEditMesh(SnapData_EditMesh *sod,
BM_mesh_elem_table_ensure(em->bm, BM_EDGE | BM_VERT);
BM_mesh_elem_index_ensure(em->bm, BM_EDGE | BM_VERT);
BLI_bvhtree_find_nearest_projected(sod->bvhtree[1],
lpmat,
nearest2d.pmat_local.ptr(),
sctx->runtime.win_size,
sctx->runtime.mval,
clip_planes_local,
sctx->runtime.clip_plane_len,
reinterpret_cast<float(*)[4]>(nearest2d.clip_planes.data()),
nearest2d.clip_planes.size(),
&nearest,
cb_snap_edge,
&nearest2d);
@ -703,21 +641,18 @@ static eSnapMode snapEditMesh(SnapData_EditMesh *sod,
}
if (nearest.index != -1) {
*dist_px_sq = nearest.dist_sq;
copy_v3_v3(sctx->ret.loc, nearest.co);
copy_v3_v3(sctx->ret.no, nearest.no);
copy_v3_v3(r_loc, nearest.co);
mul_m4_v3(obmat, r_loc);
if (r_no) {
float imat[4][4];
invert_m4_m4(imat, obmat);
mul_m4_v3(obmat, sctx->ret.loc);
copy_v3_v3(r_no, nearest.no);
mul_transposed_mat3_m4_v3(imat, r_no);
normalize_v3(r_no);
}
if (r_index) {
*r_index = nearest.index;
}
float imat[4][4];
invert_m4_m4(imat, obmat);
mul_transposed_mat3_m4_v3(imat, sctx->ret.no);
normalize_v3(sctx->ret.no);
sctx->ret.dist_px_sq = nearest.dist_sq;
sctx->ret.index = nearest.index;
return elem;
}
@ -747,50 +682,20 @@ eSnapMode snap_object_editmesh(SnapObjectContext *sctx,
if (snap_mode_used & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT |
SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_VERTEX))
{
elem = snapEditMesh(sod,
sctx,
em,
obmat,
snap_to_flag,
&sctx->ret.dist_px_sq,
sctx->ret.loc,
sctx->ret.no,
&sctx->ret.index);
elem = snapEditMesh(sod, sctx, em, obmat, snap_to_flag);
if (elem) {
return elem;
}
}
if (snap_mode_used & SCE_SNAP_MODE_FACE) {
if (raycastEditMesh(sod,
sctx,
em,
obmat,
sctx->runtime.object_index++,
/* read/write args */
&sctx->ret.ray_depth_max,
/* return args */
sctx->ret.loc,
sctx->ret.no,
&sctx->ret.index,
sctx->ret.hit_list))
{
if (raycastEditMesh(sod, sctx, em, obmat, sctx->runtime.object_index++)) {
return SCE_SNAP_MODE_FACE;
}
}
if (snap_mode_used & SCE_SNAP_MODE_FACE_NEAREST) {
if (nearest_world_editmesh(sod,
sctx,
em,
obmat,
sctx->runtime.init_co,
sctx->runtime.curr_co,
&sctx->ret.dist_px_sq,
sctx->ret.loc,
sctx->ret.no,
&sctx->ret.index))
{
if (nearest_world_editmesh(sod, sctx, em, obmat)) {
return SCE_SNAP_MODE_FACE_NEAREST;
}
}

View File

@ -18,8 +18,7 @@
#include "transform_snap_object.hh"
using blender::float3;
using blender::Span;
using namespace blender;
/* -------------------------------------------------------------------- */
/** \name Snap Object Data
@ -87,14 +86,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
const Mesh *me_eval,
const float obmat[4][4],
const uint ob_index,
bool use_hide,
/* read/write args */
float *ray_depth,
/* return args */
float r_loc[3],
float r_no[3],
int *r_index,
ListBase *r_hit_list)
bool use_hide)
{
bool retval = false;
@ -116,7 +108,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
/* local scale in normal direction */
local_scale = normalize_v3(ray_normal_local);
local_depth = *ray_depth;
local_depth = sctx->ret.ray_depth_max;
if (local_depth != BVH_RAYCAST_DIST_MAX) {
local_depth *= local_scale;
}
@ -157,7 +149,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
}
BLI_assert(treedata.raycast_callback != nullptr);
if (r_hit_list) {
if (sctx->ret.hit_list) {
RayCastAll_Data data;
data.bvhdata = &treedata;
@ -166,11 +158,16 @@ static bool raycastMesh(SnapObjectContext *sctx,
data.len_diff = len_diff;
data.local_scale = local_scale;
data.ob_uuid = ob_index;
data.hit_list = r_hit_list;
data.hit_list = sctx->ret.hit_list;
void *hit_last_prev = data.hit_list->last;
BLI_bvhtree_ray_cast_all(
treedata.tree, ray_start_local, ray_normal_local, 0.0f, *ray_depth, raycast_all_cb, &data);
BLI_bvhtree_ray_cast_all(treedata.tree,
ray_start_local,
ray_normal_local,
0.0f,
sctx->ret.ray_depth_max,
raycast_all_cb,
&data);
retval = hit_last_prev != data.hit_list->last;
}
@ -191,24 +188,18 @@ static bool raycastMesh(SnapObjectContext *sctx,
{
hit.dist += len_diff;
hit.dist /= local_scale;
if (hit.dist <= *ray_depth) {
*ray_depth = hit.dist;
copy_v3_v3(r_loc, hit.co);
if (hit.dist <= sctx->ret.ray_depth_max) {
copy_v3_v3(sctx->ret.loc, hit.co);
copy_v3_v3(sctx->ret.no, hit.no);
/* Back to world-space. */
mul_m4_v3(obmat, r_loc);
mul_m4_v3(obmat, sctx->ret.loc);
if (r_no) {
copy_v3_v3(r_no, hit.no);
mul_transposed_mat3_m4_v3(imat, r_no);
normalize_v3(r_no);
}
mul_transposed_mat3_m4_v3(imat, sctx->ret.no);
normalize_v3(sctx->ret.no);
sctx->ret.ray_depth_max = hit.dist;
sctx->ret.index = looptri_polys[hit.index];
retval = true;
if (r_index) {
*r_index = looptri_polys[hit.index];
}
}
}
}
@ -225,13 +216,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
static bool nearest_world_mesh(SnapObjectContext *sctx,
const Mesh *me_eval,
const float (*obmat)[4],
bool use_hide,
const float init_co[3],
const float curr_co[3],
float *r_dist_sq,
float *r_loc,
float *r_no,
int *r_index)
bool use_hide)
{
BVHTreeFromMesh treedata;
snap_object_data_mesh_get(me_eval, use_hide, &treedata);
@ -239,17 +224,7 @@ static bool nearest_world_mesh(SnapObjectContext *sctx,
return false;
}
return nearest_world_tree(sctx,
treedata.tree,
treedata.nearest_callback,
&treedata,
obmat,
init_co,
curr_co,
r_dist_sq,
r_loc,
r_no,
r_index);
return nearest_world_tree(sctx, treedata.tree, treedata.nearest_callback, &treedata, obmat);
}
/** \} */
@ -391,10 +366,7 @@ static void cb_mlooptri_verts_get(const int index, const Nearest2dUserData *data
r_v_index[2] = corner_verts[looptri->tri[2]];
}
void nearest2d_data_init_mesh(const Mesh *mesh,
bool is_persp,
bool use_backface_culling,
Nearest2dUserData *r_nearest2d)
void nearest2d_data_init_mesh(const Mesh *mesh, Nearest2dUserData *r_nearest2d)
{
r_nearest2d->get_vert_co = cb_mvert_co_get;
r_nearest2d->get_edge_verts_index = cb_medge_verts_get;
@ -408,9 +380,6 @@ void nearest2d_data_init_mesh(const Mesh *mesh,
r_nearest2d->corner_verts = mesh->corner_verts().data();
r_nearest2d->corner_edges = mesh->corner_edges().data();
r_nearest2d->looptris = mesh->looptris().data();
r_nearest2d->is_persp = is_persp;
r_nearest2d->use_backface_culling = use_backface_culling;
}
/** \} */
@ -424,28 +393,20 @@ eSnapMode snap_polygon_mesh(SnapObjectContext *sctx,
ID *id,
const float obmat[4][4],
eSnapMode snap_to_flag,
int polygon,
const float clip_planes_local[MAX_CLIPPLANE_LEN][4])
int polygon)
{
eSnapMode elem = SCE_SNAP_MODE_NONE;
Mesh *mesh_eval = reinterpret_cast<Mesh *>(id);
float lpmat[4][4];
mul_m4_m4m4(lpmat, sctx->runtime.pmat, obmat);
DistProjectedAABBPrecalc neasrest_precalc;
dist_squared_to_projected_aabb_precalc(
&neasrest_precalc, lpmat, sctx->runtime.win_size, sctx->runtime.mval);
Nearest2dUserData nearest2d(sctx, sctx->ret.dist_px_sq, float4x4(obmat));
nearest2d.clip_planes_get(sctx, float4x4(obmat));
nearest2d_data_init_mesh(mesh_eval, &nearest2d);
BVHTreeNearest nearest{};
nearest.index = -1;
nearest.dist_sq = sctx->ret.dist_px_sq;
Nearest2dUserData nearest2d;
nearest2d_data_init_mesh(
mesh_eval, sctx->runtime.is_persp, sctx->runtime.params.use_backface_culling, &nearest2d);
const blender::IndexRange poly = mesh_eval->polys()[polygon];
if (snap_to_flag & SCE_SNAP_MODE_EDGE) {
@ -455,9 +416,9 @@ eSnapMode snap_polygon_mesh(SnapObjectContext *sctx,
for (int i = poly.size(); i--;) {
cb_snap_edge(&nearest2d,
poly_edges[i],
&neasrest_precalc,
clip_planes_local,
sctx->runtime.clip_plane_len,
&nearest2d.nearest_precalc,
reinterpret_cast<float(*)[4]>(nearest2d.clip_planes.data()),
nearest2d.clip_planes.size(),
&nearest);
}
}
@ -467,9 +428,9 @@ eSnapMode snap_polygon_mesh(SnapObjectContext *sctx,
for (int i = poly.size(); i--;) {
cb_snap_vert(&nearest2d,
poly_verts[i],
&neasrest_precalc,
clip_planes_local,
sctx->runtime.clip_plane_len,
&nearest2d.nearest_precalc,
reinterpret_cast<float(*)[4]>(nearest2d.clip_planes.data()),
nearest2d.clip_planes.size(),
&nearest);
}
}
@ -500,13 +461,7 @@ static eSnapMode snapMesh(SnapObjectContext *sctx,
Object *ob_eval,
const Mesh *me_eval,
const float obmat[4][4],
bool use_hide,
/* read/write args */
float *dist_px_sq,
/* return args */
float r_loc[3],
float r_no[3],
int *r_index)
bool use_hide)
{
BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE);
if (me_eval->totvert == 0) {
@ -516,19 +471,11 @@ static eSnapMode snapMesh(SnapObjectContext *sctx,
return SCE_SNAP_MODE_NONE;
}
float lpmat[4][4];
mul_m4_m4m4(lpmat, sctx->runtime.pmat, obmat);
Nearest2dUserData nearest2d(sctx, sctx->ret.dist_px_sq, float4x4(obmat));
/* Test BoundBox */
if (ob_eval->data == me_eval) {
const BoundBox *bb = BKE_object_boundbox_get(ob_eval);
if (!snap_bound_box_check_dist(bb->vec[0],
bb->vec[6],
lpmat,
sctx->runtime.win_size,
sctx->runtime.mval,
*dist_px_sq))
{
const BoundBox *bb = BKE_mesh_boundbox_get(ob_eval);
if (!nearest2d.snap_boundbox(bb->vec[0], bb->vec[6])) {
return SCE_SNAP_MODE_NONE;
}
}
@ -544,32 +491,25 @@ static eSnapMode snapMesh(SnapObjectContext *sctx,
BLI_assert(treedata_dummy.cached);
}
Nearest2dUserData nearest2d;
nearest2d_data_init_mesh(
me_eval, sctx->runtime.is_persp, sctx->runtime.params.use_backface_culling, &nearest2d);
nearest2d.clip_planes_get(sctx, float4x4(obmat));
nearest2d_data_init_mesh(me_eval, &nearest2d);
BVHTreeNearest nearest{};
nearest.index = -1;
nearest.dist_sq = *dist_px_sq;
nearest.dist_sq = sctx->ret.dist_px_sq;
int last_index = nearest.index;
eSnapMode elem = SCE_SNAP_MODE_VERTEX;
float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
transpose_m4_m4(tobmat, obmat);
for (int i = sctx->runtime.clip_plane_len; i--;) {
mul_v4_m4v4(clip_planes_local[i], tobmat, sctx->runtime.clip_plane[i]);
}
if (bvhtree[1]) {
BLI_assert(sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX);
/* snap to loose verts */
BLI_bvhtree_find_nearest_projected(bvhtree[1],
lpmat,
nearest2d.pmat_local.ptr(),
sctx->runtime.win_size,
sctx->runtime.mval,
clip_planes_local,
sctx->runtime.clip_plane_len,
reinterpret_cast<float(*)[4]>(nearest2d.clip_planes.data()),
nearest2d.clip_planes.size(),
&nearest,
cb_snap_vert,
&nearest2d);
@ -580,28 +520,30 @@ static eSnapMode snapMesh(SnapObjectContext *sctx,
if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE) {
if (bvhtree[0]) {
/* Snap to loose edges. */
BLI_bvhtree_find_nearest_projected(bvhtree[0],
lpmat,
sctx->runtime.win_size,
sctx->runtime.mval,
clip_planes_local,
sctx->runtime.clip_plane_len,
&nearest,
cb_snap_edge,
&nearest2d);
BLI_bvhtree_find_nearest_projected(
bvhtree[0],
nearest2d.pmat_local.ptr(),
sctx->runtime.win_size,
sctx->runtime.mval,
reinterpret_cast<float(*)[4]>(nearest2d.clip_planes.data()),
nearest2d.clip_planes.size(),
&nearest,
cb_snap_edge,
&nearest2d);
}
if (treedata.tree) {
/* Snap to looptris. */
BLI_bvhtree_find_nearest_projected(treedata.tree,
lpmat,
sctx->runtime.win_size,
sctx->runtime.mval,
clip_planes_local,
sctx->runtime.clip_plane_len,
&nearest,
cb_snap_tri_edges,
&nearest2d);
BLI_bvhtree_find_nearest_projected(
treedata.tree,
nearest2d.pmat_local.ptr(),
sctx->runtime.win_size,
sctx->runtime.mval,
reinterpret_cast<float(*)[4]>(nearest2d.clip_planes.data()),
nearest2d.clip_planes.size(),
&nearest,
cb_snap_tri_edges,
&nearest2d);
}
if (last_index != nearest.index) {
@ -612,48 +554,47 @@ static eSnapMode snapMesh(SnapObjectContext *sctx,
BLI_assert(sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX);
if (bvhtree[0]) {
/* Snap to loose edge verts. */
BLI_bvhtree_find_nearest_projected(bvhtree[0],
lpmat,
sctx->runtime.win_size,
sctx->runtime.mval,
clip_planes_local,
sctx->runtime.clip_plane_len,
&nearest,
cb_snap_edge_verts,
&nearest2d);
BLI_bvhtree_find_nearest_projected(
bvhtree[0],
nearest2d.pmat_local.ptr(),
sctx->runtime.win_size,
sctx->runtime.mval,
reinterpret_cast<float(*)[4]>(nearest2d.clip_planes.data()),
nearest2d.clip_planes.size(),
&nearest,
cb_snap_edge_verts,
&nearest2d);
}
if (treedata.tree) {
/* Snap to looptri verts. */
BLI_bvhtree_find_nearest_projected(treedata.tree,
lpmat,
sctx->runtime.win_size,
sctx->runtime.mval,
clip_planes_local,
sctx->runtime.clip_plane_len,
&nearest,
cb_snap_tri_verts,
&nearest2d);
BLI_bvhtree_find_nearest_projected(
treedata.tree,
nearest2d.pmat_local.ptr(),
sctx->runtime.win_size,
sctx->runtime.mval,
reinterpret_cast<float(*)[4]>(nearest2d.clip_planes.data()),
nearest2d.clip_planes.size(),
&nearest,
cb_snap_tri_verts,
&nearest2d);
}
}
if (nearest.index != -1) {
*dist_px_sq = nearest.dist_sq;
copy_v3_v3(sctx->ret.loc, nearest.co);
copy_v3_v3(sctx->ret.no, nearest.no);
copy_v3_v3(r_loc, nearest.co);
mul_m4_v3(obmat, r_loc);
mul_m4_v3(obmat, sctx->ret.loc);
if (r_no) {
float imat[4][4];
invert_m4_m4(imat, obmat);
float imat[3][3];
copy_m3_m4(imat, obmat);
invert_m3(imat);
mul_transposed_m3_v3(imat, sctx->ret.no);
normalize_v3(sctx->ret.no);
copy_v3_v3(r_no, nearest.no);
mul_transposed_mat3_m4_v3(imat, r_no);
normalize_v3(r_no);
}
if (r_index) {
*r_index = nearest.index;
}
sctx->ret.index = nearest.index;
sctx->ret.dist_px_sq = nearest.dist_sq;
return elem;
}
@ -694,51 +635,20 @@ eSnapMode snap_object_mesh(SnapObjectContext *sctx,
if (snap_mode_used & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT |
SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_VERTEX))
{
elem = snapMesh(sctx,
ob_eval,
mesh_eval,
obmat,
use_hide,
&sctx->ret.dist_px_sq,
sctx->ret.loc,
sctx->ret.no,
&sctx->ret.index);
elem = snapMesh(sctx, ob_eval, mesh_eval, obmat, use_hide);
if (elem) {
return elem;
}
}
if (snap_mode_used & SCE_SNAP_MODE_FACE) {
if (raycastMesh(sctx,
ob_eval,
mesh_eval,
obmat,
sctx->runtime.object_index++,
use_hide,
/* read/write args */
&sctx->ret.ray_depth_max,
/* return args */
sctx->ret.loc,
sctx->ret.no,
&sctx->ret.index,
sctx->ret.hit_list))
{
if (raycastMesh(sctx, ob_eval, mesh_eval, obmat, sctx->runtime.object_index++, use_hide)) {
return SCE_SNAP_MODE_FACE;
}
}
if (snap_mode_used & SCE_SNAP_MODE_FACE_NEAREST) {
if (nearest_world_mesh(sctx,
mesh_eval,
obmat,
use_hide,
sctx->runtime.init_co,
sctx->runtime.curr_co,
&sctx->ret.dist_px_sq,
sctx->ret.loc,
sctx->ret.no,
&sctx->ret.index))
{
if (nearest_world_mesh(sctx, mesh_eval, obmat, use_hide)) {
return SCE_SNAP_MODE_FACE_NEAREST;
}
}

View File

@ -1,5 +1,5 @@
/* SPDX-FileCopyrightText: 2019 Stefano Quer
SPDX-FileCopyrightText: 2022 Blender Foundation
* SPDX-FileCopyrightText: 2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-3.0-or-later
*

View File

@ -1,5 +1,5 @@
/* SPDX-FileCopyrightText: 2019 Stefano Quer
SPDX-FileCopyrightText: 2022 Blender Foundation
* SPDX-FileCopyrightText: 2022 Blender Foundation
*
* SPDX-License-Identifier: GPL-3.0-or-later
*

View File

@ -1602,7 +1602,7 @@ static const EnumPropertyItem pack_shape_method_items[] = {
* \note #ED_UVPACK_PIN_NONE is exposed as a boolean "pin".
* \note #ED_UVPACK_PIN_IGNORE is intentionally not exposed as it is confusing from the UI level
* (users can simply not select these islands).
* The option is kept kept internally because it's used for live unwrap.
* The option is kept internally because it's used for live unwrap.
*/
static const EnumPropertyItem pinned_islands_method_items[] = {
{ED_UVPACK_PIN_LOCK_SCALE, "SCALE", 0, "Scale", "Pinned islands won't rescale"},

View File

@ -110,7 +110,7 @@ class MTLUniformBuf;
class MTLBuffer {
public:
/* NOTE: ListBase API is not used due to cutsom destructor operation required to release
/* NOTE: ListBase API is not used due to custom destructor operation required to release
* Metal objective C buffer resource. */
gpu::MTLBuffer *next, *prev;

View File

@ -200,7 +200,7 @@ static void test_framebuffer_scissor_test()
}
GPU_TEST(framebuffer_scissor_test);
/* Color each side of a cubemap with a different color. */
/* Color each side of a cube-map with a different color. */
static void test_framebuffer_cube()
{
const int SIZE = 32;

View File

@ -28,12 +28,12 @@ namespace blender::gpu {
*
* When using a GPU_TEXTURE_CUBE as an frame buffer attachment it will be used as a
* GPU_TEXTURE_2D_ARRAY. eg only a single side of the cube map will be attached. But when bound as
* a shader resource the cubemap will be used.
* a shader resource the cube-map will be used.
*/
enum class eImageViewUsage {
/** Image View will be used as a bindable shader resource. */
ShaderBinding,
/** Image View will be used as an framebuffer attachment. */
/** Image View will be used as an frame-buffer attachment. */
Attachment,
};

View File

@ -188,12 +188,12 @@ using FormatF10 = FloatingPointFormat<false, 5, 5>;
*/
template<
/**
* FloatingPointFormat of the the value that is converted to.
* FloatingPointFormat of the value that is converted to.
*/
typename DestinationFormat,
/**
* FloatingPointFormat of the the value that is converted from.
* FloatingPointFormat of the value that is converted from.
*/
typename SourceFormat,

View File

@ -180,11 +180,12 @@ static ImBuf *get_oiio_ibuf(ImageInput *in, const ReadContext &ctx, char colorsp
const ImageSpec &spec = in->spec();
const int width = spec.width;
const int height = spec.height;
const int channels = spec.nchannels;
const bool has_alpha = spec.alpha_channel != -1;
const bool is_float = spec.format.basesize() > 1;
if (channels < 1 || channels > 4) {
/* Only a maximum of 4 channels are supported by ImBuf. */
const int channels = spec.nchannels <= 4 ? spec.nchannels : 4;
if (channels < 1) {
return nullptr;
}

View File

@ -81,7 +81,7 @@ class AbcObjectReader {
/* XXX - TODO(kevindietrich) : this references stack memory... */
ImportSettings *m_settings;
/* This is initialised from the ImportSettings above on construction. It will need to be removed
/* This is initialized from the ImportSettings above on construction. It will need to be removed
* once we fix the stack memory reference situation. */
bool m_is_reading_a_file_sequence = false;

View File

@ -1661,7 +1661,7 @@ typedef struct NodeGeometrySimulationOutput {
#ifdef __cplusplus
blender::Span<NodeSimulationItem> items_span() const;
blender::MutableSpan<NodeSimulationItem> items_span_for_write();
blender::MutableSpan<NodeSimulationItem> items_span();
blender::IndexRange items_range() const;
#endif
} NodeGeometrySimulationOutput;

View File

@ -25,6 +25,10 @@ struct Object;
struct PreviewImage;
struct Tex;
/* -------------------------------------------------------------------- */
/** \name #MTex
* \{ */
typedef struct MTex {
DNA_DEFINE_CXX_METHODS(MTex)
@ -60,6 +64,12 @@ typedef struct MTex {
float twistfac;
} MTex;
/** \} */
/* -------------------------------------------------------------------- */
/** \name #ColorBand
* \{ */
#ifndef DNA_USHORT_FIX
# define DNA_USHORT_FIX
/**
@ -88,6 +98,12 @@ typedef struct ColorBand {
CBData data[32];
} ColorBand;
/** \} */
/* -------------------------------------------------------------------- */
/** \name #PointDensity
* \{ */
typedef struct PointDensity {
DNA_DEFINE_CXX_METHODS(PointDensity)
@ -138,6 +154,12 @@ typedef struct PointDensity {
struct CurveMapping *falloff_curve;
} PointDensity;
/** \} */
/* -------------------------------------------------------------------- */
/** \name #Tex
* \{ */
typedef struct Tex {
DNA_DEFINE_CXX_METHODS(Tex)
@ -235,221 +257,301 @@ typedef struct ColorMapping {
char _pad[4];
} ColorMapping;
/* texmap->flag */
#define TEXMAP_CLIP_MIN 1
#define TEXMAP_CLIP_MAX 2
#define TEXMAP_UNIT_MATRIX 4
/** \} */
/* texmap->type */
#define TEXMAP_TYPE_POINT 0
#define TEXMAP_TYPE_TEXTURE 1
#define TEXMAP_TYPE_VECTOR 2
#define TEXMAP_TYPE_NORMAL 3
/* -------------------------------------------------------------------- */
/** \name #TexMapping Types
* \{ */
/* colormap->flag */
#define COLORMAP_USE_RAMP 1
/** #TexMapping::flag bit-mask. */
enum {
TEXMAP_CLIP_MIN = 1 << 0,
TEXMAP_CLIP_MAX = 1 << 1,
TEXMAP_UNIT_MATRIX = 1 << 2,
};
/* **************** TEX ********************* */
/** #TexMapping::type. */
enum {
TEXMAP_TYPE_POINT = 0,
TEXMAP_TYPE_TEXTURE = 1,
TEXMAP_TYPE_VECTOR = 2,
TEXMAP_TYPE_NORMAL = 3,
};
/* type */
#define TEX_CLOUDS 1
#define TEX_WOOD 2
#define TEX_MARBLE 3
#define TEX_MAGIC 4
#define TEX_BLEND 5
#define TEX_STUCCI 6
#define TEX_NOISE 7
#define TEX_IMAGE 8
// #define TEX_PLUGIN 9 /* Deprecated */
// #define TEX_ENVMAP 10 /* Deprecated */
#define TEX_MUSGRAVE 11
#define TEX_VORONOI 12
#define TEX_DISTNOISE 13
// #define TEX_POINTDENSITY 14 /* Deprecated */
// #define TEX_VOXELDATA 15 /* Deprecated */
// #define TEX_OCEAN 16 /* Deprecated */
/** #ColorMapping::flag bit-mask. */
enum {
COLORMAP_USE_RAMP = 1,
};
/* musgrave stype */
#define TEX_MFRACTAL 0
#define TEX_RIDGEDMF 1
#define TEX_HYBRIDMF 2
#define TEX_FBM 3
#define TEX_HTERRAIN 4
/** \} */
/* newnoise: noisebasis 1 & 2 */
#define TEX_BLENDER 0
#define TEX_STDPERLIN 1
#define TEX_NEWPERLIN 2
#define TEX_VORONOI_F1 3
#define TEX_VORONOI_F2 4
#define TEX_VORONOI_F3 5
#define TEX_VORONOI_F4 6
#define TEX_VORONOI_F2F1 7
#define TEX_VORONOI_CRACKLE 8
#define TEX_CELLNOISE 14
/* -------------------------------------------------------------------- */
/** \name #Tex Types
* \{ */
/* newnoise: Voronoi distance metrics, vn_distm */
#define TEX_DISTANCE 0
#define TEX_DISTANCE_SQUARED 1
#define TEX_MANHATTAN 2
#define TEX_CHEBYCHEV 3
#define TEX_MINKOVSKY_HALF 4
#define TEX_MINKOVSKY_FOUR 5
#define TEX_MINKOVSKY 6
/** #Tex::type. */
enum {
TEX_CLOUDS = 1,
TEX_WOOD = 2,
TEX_MARBLE = 3,
TEX_MAGIC = 4,
TEX_BLEND = 5,
TEX_STUCCI = 6,
TEX_NOISE = 7,
TEX_IMAGE = 8,
// TEX_PLUGIN = 9, /* Deprecated */
// TEX_ENVMAP = 10, /* Deprecated */
TEX_MUSGRAVE = 11,
TEX_VORONOI = 12,
TEX_DISTNOISE = 13,
// TEX_POINTDENSITY = 14, /* Deprecated */
// TEX_VOXELDATA = 15, /* Deprecated */
// TEX_OCEAN = 16, /* Deprecated */
};
/* imaflag */
#define TEX_INTERPOL (1 << 0)
#define TEX_USEALPHA (1 << 1)
#define TEX_MIPMAP (1 << 2)
#define TEX_IMAROT (1 << 4)
#define TEX_CALCALPHA (1 << 5)
#define TEX_NORMALMAP (1 << 11)
#define TEX_GAUSS_MIP (1 << 12)
#define TEX_FILTER_MIN (1 << 13)
#define TEX_DERIVATIVEMAP (1 << 14)
/** #Tex::stype musgrave. */
enum {
TEX_MFRACTAL = 0,
TEX_RIDGEDMF = 1,
TEX_HYBRIDMF = 2,
TEX_FBM = 3,
TEX_HTERRAIN = 4,
};
/* texfilter */
#define TXF_BOX 0 /* Blender's old texture filtering method. */
#define TXF_EWA 1
#define TXF_FELINE 2
#define TXF_AREA 3
/** #Tex::noisebasis, #Tex::noisebasis2. */
enum {
TEX_BLENDER = 0,
TEX_STDPERLIN = 1,
TEX_NEWPERLIN = 2,
TEX_VORONOI_F1 = 3,
TEX_VORONOI_F2 = 4,
TEX_VORONOI_F3 = 5,
TEX_VORONOI_F4 = 6,
TEX_VORONOI_F2F1 = 7,
TEX_VORONOI_CRACKLE = 8,
TEX_CELLNOISE = 14,
};
/** #Tex::vn_distm voronoi distance metrics. */
enum {
TEX_DISTANCE = 0,
TEX_DISTANCE_SQUARED = 1,
TEX_MANHATTAN = 2,
TEX_CHEBYCHEV = 3,
TEX_MINKOVSKY_HALF = 4,
TEX_MINKOVSKY_FOUR = 5,
TEX_MINKOVSKY = 6,
};
/** #Tex::imaflag bit-mask. */
enum {
TEX_INTERPOL = 1 << 0,
TEX_USEALPHA = 1 << 1,
TEX_MIPMAP = 1 << 2,
TEX_IMAROT = 1 << 4,
TEX_CALCALPHA = 1 << 5,
TEX_NORMALMAP = 1 << 11,
TEX_GAUSS_MIP = 1 << 12,
TEX_FILTER_MIN = 1 << 13,
TEX_DERIVATIVEMAP = 1 << 14,
};
/** #Tex::texfilter type. */
enum {
TXF_BOX = 0, /* Blender's old texture filtering method. */
TXF_EWA = 1,
TXF_FELINE = 2,
TXF_AREA = 3,
};
/** #Tex::flag bit-mask. */
enum {
TEX_COLORBAND = 1 << 0,
TEX_FLIPBLEND = 1 << 1,
TEX_NEGALPHA = 1 << 2,
TEX_CHECKER_ODD = 1 << 3,
TEX_CHECKER_EVEN = 1 << 4,
TEX_PRV_ALPHA = 1 << 5,
TEX_PRV_NOR = 1 << 6,
TEX_REPEAT_XMIR = 1 << 7,
TEX_REPEAT_YMIR = 1 << 8,
TEX_DS_EXPAND = 1 << 9,
TEX_NO_CLAMP = 1 << 10,
};
/* flag */
#define TEX_COLORBAND (1 << 0)
#define TEX_FLIPBLEND (1 << 1)
#define TEX_NEGALPHA (1 << 2)
#define TEX_CHECKER_ODD (1 << 3)
#define TEX_CHECKER_EVEN (1 << 4)
#define TEX_PRV_ALPHA (1 << 5)
#define TEX_PRV_NOR (1 << 6)
#define TEX_REPEAT_XMIR (1 << 7)
#define TEX_REPEAT_YMIR (1 << 8)
#define TEX_FLAG_MASK \
(TEX_COLORBAND | TEX_FLIPBLEND | TEX_NEGALPHA | TEX_CHECKER_ODD | TEX_CHECKER_EVEN | \
TEX_PRV_ALPHA | TEX_PRV_NOR | TEX_REPEAT_XMIR | TEX_REPEAT_YMIR)
#define TEX_DS_EXPAND (1 << 9)
#define TEX_NO_CLAMP (1 << 10)
/* extend (starts with 1 because of backward comp.) */
#define TEX_EXTEND 1
#define TEX_CLIP 2
#define TEX_REPEAT 3
#define TEX_CLIPCUBE 4
#define TEX_CHECKER 5
/** #Tex::extend (starts with 1 because of backward compatibility). */
enum {
TEX_EXTEND = 1,
TEX_CLIP = 2,
TEX_REPEAT = 3,
TEX_CLIPCUBE = 4,
TEX_CHECKER = 5,
};
/* noisetype */
#define TEX_NOISESOFT 0
#define TEX_NOISEPERL 1
/** #Tex::noisetype type. */
enum {
TEX_NOISESOFT = 0,
TEX_NOISEPERL = 1,
};
/* tex->noisebasis2 in texture.c - wood waveforms */
#define TEX_SIN 0
#define TEX_SAW 1
#define TEX_TRI 2
/** #Tex::noisebasis2 wood waveforms. */
enum {
TEX_SIN = 0,
TEX_SAW = 1,
TEX_TRI = 2,
};
/* tex->stype in texture.c - wood types */
#define TEX_BAND 0
#define TEX_RING 1
#define TEX_BANDNOISE 2
#define TEX_RINGNOISE 3
/** #Tex::stype wood types. */
enum {
TEX_BAND = 0,
TEX_RING = 1,
TEX_BANDNOISE = 2,
TEX_RINGNOISE = 3,
};
/* tex->stype in texture.c - cloud types */
#define TEX_DEFAULT 0
#define TEX_COLOR 1
/** #Tex::stype cloud types. */
enum {
TEX_DEFAULT = 0,
TEX_COLOR = 1,
};
/* tex->stype in texture.c - marble types */
#define TEX_SOFT 0
#define TEX_SHARP 1
#define TEX_SHARPER 2
/** #Tex::stype marble types. */
enum {
TEX_SOFT = 0,
TEX_SHARP = 1,
TEX_SHARPER = 2,
};
/* tex->stype in texture.c - blend types */
#define TEX_LIN 0
#define TEX_QUAD 1
#define TEX_EASE 2
#define TEX_DIAG 3
#define TEX_SPHERE 4
#define TEX_HALO 5
#define TEX_RAD 6
/** #Tex::stype blend types. */
enum {
TEX_LIN = 0,
TEX_QUAD = 1,
TEX_EASE = 2,
TEX_DIAG = 3,
TEX_SPHERE = 4,
TEX_HALO = 5,
TEX_RAD = 6,
};
/* tex->stype in texture.c - stucci types */
#define TEX_PLASTIC 0
#define TEX_WALLIN 1
#define TEX_WALLOUT 2
/** #Tex::stype stucci types. */
enum {
TEX_PLASTIC = 0,
TEX_WALLIN = 1,
TEX_WALLOUT = 2,
};
/* tex->stype in texture.c - voronoi types */
#define TEX_INTENSITY 0
#define TEX_COL1 1
#define TEX_COL2 2
#define TEX_COL3 3
/** #Tex::vn_coltype voronoi color types. */
enum {
TEX_INTENSITY = 0,
TEX_COL1 = 1,
TEX_COL2 = 2,
TEX_COL3 = 3,
};
/* mtex->normapspace */
#define MTEX_NSPACE_CAMERA 0
#define MTEX_NSPACE_WORLD 1
#define MTEX_NSPACE_OBJECT 2
#define MTEX_NSPACE_TANGENT 3
/** Return value. */
enum {
TEX_INT = 0,
TEX_RGB = 1,
};
/* wrap */
#define MTEX_FLAT 0
#define MTEX_CUBE 1
#define MTEX_TUBE 2
#define MTEX_SPHERE 3
/**
* - #Material::pr_texture
* - #Light::pr_texture
* - #World::pr_texture
* - #FreestyleLineStyle::pr_texture
*/
enum {
TEX_PR_TEXTURE = 0,
TEX_PR_OTHER = 1,
TEX_PR_BOTH = 2,
};
/* return value */
#define TEX_INT 0
#define TEX_RGB 1
/** \} */
/* pr_texture in material, world, light. */
#define TEX_PR_TEXTURE 0
#define TEX_PR_OTHER 1
#define TEX_PR_BOTH 2
/* -------------------------------------------------------------------- */
/** \name #TexMapping Types
* \{ */
/* **************** MTEX ********************* */
/**
* #TexMapping::projx
* #TexMapping::projy
* #TexMapping::projz
*/
enum {
PROJ_N = 0,
PROJ_X = 1,
PROJ_Y = 2,
PROJ_Z = 3,
};
/* proj */
#define PROJ_N 0
#define PROJ_X 1
#define PROJ_Y 2
#define PROJ_Z 3
/** \} */
/* blendtype */
#define MTEX_BLEND 0
#define MTEX_MUL 1
#define MTEX_ADD 2
#define MTEX_SUB 3
#define MTEX_DIV 4
#define MTEX_DARK 5
#define MTEX_DIFF 6
#define MTEX_LIGHT 7
#define MTEX_SCREEN 8
#define MTEX_OVERLAY 9
#define MTEX_BLEND_HUE 10
#define MTEX_BLEND_SAT 11
#define MTEX_BLEND_VAL 12
#define MTEX_BLEND_COLOR 13
#define MTEX_SOFT_LIGHT 15
#define MTEX_LIN_LIGHT 16
/* -------------------------------------------------------------------- */
/** \name #MTex Types
* \{ */
/* brush_map_mode */
#define MTEX_MAP_MODE_VIEW 0
#define MTEX_MAP_MODE_TILED 1
#define MTEX_MAP_MODE_3D 2
#define MTEX_MAP_MODE_AREA 3
#define MTEX_MAP_MODE_RANDOM 4
#define MTEX_MAP_MODE_STENCIL 5
/** #MTex::mapping. */
enum {
MTEX_FLAT = 0,
MTEX_CUBE = 1,
MTEX_TUBE = 2,
MTEX_SPHERE = 3,
};
/* brush_angle_mode */
#define MTEX_ANGLE_RANDOM 1
#define MTEX_ANGLE_RAKE 2
/** #MTex::blendtype. */
enum {
MTEX_BLEND = 0,
MTEX_MUL = 1,
MTEX_ADD = 2,
MTEX_SUB = 3,
MTEX_DIV = 4,
MTEX_DARK = 5,
MTEX_DIFF = 6,
MTEX_LIGHT = 7,
MTEX_SCREEN = 8,
MTEX_OVERLAY = 9,
MTEX_BLEND_HUE = 10,
MTEX_BLEND_SAT = 11,
MTEX_BLEND_VAL = 12,
MTEX_BLEND_COLOR = 13,
MTEX_SOFT_LIGHT = 15,
MTEX_LIN_LIGHT = 16,
};
/* **************** ColorBand ********************* */
/** #MTex::brush_map_mode. */
enum {
MTEX_MAP_MODE_VIEW = 0,
MTEX_MAP_MODE_TILED = 1,
MTEX_MAP_MODE_3D = 2,
MTEX_MAP_MODE_AREA = 3,
MTEX_MAP_MODE_RANDOM = 4,
MTEX_MAP_MODE_STENCIL = 5,
};
/** color-mode. */
/** #MTex::brush_angle_mode. */
enum {
MTEX_ANGLE_RANDOM = 1,
MTEX_ANGLE_RAKE = 2,
};
/** \} */
/* -------------------------------------------------------------------- */
/** \name #ColorBand Types
* \{ */
/** #ColorBand::color_mode. */
enum {
COLBAND_BLEND_RGB = 0,
COLBAND_BLEND_HSV = 1,
COLBAND_BLEND_HSL = 2,
};
/** Interpolation. */
/** #ColorBand::ipotype (interpolation). */
enum {
COLBAND_INTERP_LINEAR = 0,
COLBAND_INTERP_EASE = 1,
@ -458,7 +560,7 @@ enum {
COLBAND_INTERP_CONSTANT = 4,
};
/** Color interpolation. */
/** #ColorBand::ipotype_hue (hue interpolation). */
enum {
COLBAND_HUE_NEAR = 0,
COLBAND_HUE_FAR = 1,
@ -466,38 +568,52 @@ enum {
COLBAND_HUE_CCW = 3,
};
/* **************** PointDensity ********************* */
/** \} */
/* source */
#define TEX_PD_PSYS 0
#define TEX_PD_OBJECT 1
#define TEX_PD_FILE 2
/* -------------------------------------------------------------------- */
/** \name #PointDensity Types
* \{ */
/* falloff_type */
#define TEX_PD_FALLOFF_STD 0
#define TEX_PD_FALLOFF_SMOOTH 1
#define TEX_PD_FALLOFF_SOFT 2
#define TEX_PD_FALLOFF_CONSTANT 3
#define TEX_PD_FALLOFF_ROOT 4
#define TEX_PD_FALLOFF_PARTICLE_AGE 5
#define TEX_PD_FALLOFF_PARTICLE_VEL 6
/** #PointDensity::source. */
enum {
TEX_PD_PSYS = 0,
TEX_PD_OBJECT = 1,
TEX_PD_FILE = 2,
};
/* psys_cache_space */
#define TEX_PD_OBJECTLOC 0
#define TEX_PD_OBJECTSPACE 1
#define TEX_PD_WORLDSPACE 2
/** #PointDensity::falloff_type. */
enum {
TEX_PD_FALLOFF_STD = 0,
TEX_PD_FALLOFF_SMOOTH = 1,
TEX_PD_FALLOFF_SOFT = 2,
TEX_PD_FALLOFF_CONSTANT = 3,
TEX_PD_FALLOFF_ROOT = 4,
TEX_PD_FALLOFF_PARTICLE_AGE = 5,
TEX_PD_FALLOFF_PARTICLE_VEL = 6,
};
/* flag */
#define TEX_PD_TURBULENCE 1
#define TEX_PD_FALLOFF_CURVE 2
/** #PointDensity::psys_cache_space. */
enum {
TEX_PD_OBJECTLOC = 0,
TEX_PD_OBJECTSPACE = 1,
TEX_PD_WORLDSPACE = 2,
};
/* noise_influence */
#define TEX_PD_NOISE_STATIC 0
/* #define TEX_PD_NOISE_VEL 1 */ /* Deprecated */
/* #define TEX_PD_NOISE_AGE 2 */ /* Deprecated */
/* #define TEX_PD_NOISE_TIME 3 */ /* Deprecated */
/** #PointDensity::flag. */
enum {
TEX_PD_TURBULENCE = 1 << 0,
TEX_PD_FALLOFF_CURVE = 1 << 1,
};
/** color_source. */
/** #PointDensity::noise_influence. */
enum {
TEX_PD_NOISE_STATIC = 0,
// TEX_PD_NOISE_VEL = 1, /* Deprecated. */
// TEX_PD_NOISE_AGE = 2, /* Deprecated. */
// TEX_PD_NOISE_TIME = 3, /* Deprecated. */
};
/** #PointDensity::color_source. */
enum {
TEX_PD_COLOR_CONSTANT = 0,
/* color_source: particles */
@ -510,9 +626,7 @@ enum {
TEX_PD_COLOR_VERTNOR = 3,
};
#define POINT_DATA_VEL 1
#define POINT_DATA_LIFE 2
#define POINT_DATA_COLOR 4
/** \} */
#ifdef __cplusplus
}

View File

@ -1425,8 +1425,9 @@ static char *rna_def_property_set_func(
/* C++ may require casting to an enum type. */
fprintf(f, "#ifdef __cplusplus\n");
fprintf(f,
/* If #rna_clamp_value() adds an expression like `CLAMPIS(...)` (instead of an
lvalue), #decltype() yields a reference, so that has to be removed.*/
/* If #rna_clamp_value() adds an expression like `CLAMPIS(...)`
* (instead of an `lvalue`), #decltype() yields a reference,
* so that has to be removed. */
" data->%s = %s(std::remove_reference_t<decltype(data->%s)>)",
dp->dnaname,
(dp->booleannegative) ? "!" : "",

View File

@ -91,9 +91,9 @@ static void rna_Lattice_update_data(Main * /*bmain*/, Scene * /*scene*/, Pointer
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
}
/* copy settings to editlattice,
* we could split this up differently (one update call per property)
* but for now that's overkill
/**
* Copy settings to edit-lattice, we could split this up differently
* (one update call per property) but for now that's overkill.
*/
static void rna_Lattice_update_data_editlatt(Main * /*bmain*/, Scene * /*scene*/, PointerRNA *ptr)
{

View File

@ -2202,7 +2202,7 @@ static void rna_SpaceDopeSheetEditor_action_set(PointerRNA *ptr,
}
}
else if (saction->mode == SACTCONT_SHAPEKEY) {
/* as the name says, "shapekey-level" only... */
/* As the name says, "shape-key level" only. */
if (act->idroot == ID_KE) {
saction->action = act;
}

View File

@ -46,6 +46,8 @@ class DTreeContext {
const bNode *parent_node_;
/* The current node tree. */
const bNodeTree *btree_;
/* The instance key of the parent node. NODE_INSTANCE_KEY_BASE for root contexts. */
bNodeInstanceKey instance_key_;
/* All the children contexts of this context. */
Map<const bNode *, DTreeContext *> children_;
DerivedNodeTree *derived_tree_;
@ -56,6 +58,7 @@ class DTreeContext {
const bNodeTree &btree() const;
const DTreeContext *parent_context() const;
const bNode *parent_node() const;
const bNodeInstanceKey instance_key() const;
const DTreeContext *child_context(const bNode &node) const;
const DerivedNodeTree &derived_tree() const;
bool is_root() const;
@ -76,6 +79,7 @@ class DNode {
const DTreeContext *context() const;
const bNode *bnode() const;
const bNodeInstanceKey instance_key() const;
const bNode *operator->() const;
const bNode &operator*() const;
@ -191,6 +195,14 @@ class DerivedNodeTree {
const DTreeContext &root_context() const;
Span<const bNodeTree *> used_btrees() const;
/** Returns the active context for the node tree. The active context represents the node tree
* currently being edited. In most cases, that would be the top level node tree itself, but in
* the case where the user is editing the node tree of a node group, the active context would be
* a representation of the node tree of that node group. Note that the context also stores the
* group node that the user selected to edit the node tree, so the context fully represents a
* particular instance of the node group. */
const DTreeContext &active_context() const;
/**
* \return True when there is a link cycle. Unavailable sockets are ignored.
*/
@ -205,7 +217,8 @@ class DerivedNodeTree {
private:
DTreeContext &construct_context_recursively(DTreeContext *parent_context,
const bNode *parent_node,
const bNodeTree &btree);
const bNodeTree &btree,
const bNodeInstanceKey instance_key);
void destruct_context_recursively(DTreeContext *context);
void foreach_node_in_context_recursive(const DTreeContext &context,
@ -240,6 +253,11 @@ inline const bNode *DTreeContext::parent_node() const
return parent_node_;
}
inline const bNodeInstanceKey DTreeContext::instance_key() const
{
return instance_key_;
}
inline const DTreeContext *DTreeContext::child_context(const bNode &node) const
{
return children_.lookup_default(&node, nullptr);

View File

@ -325,6 +325,11 @@ static void duplicate_curves(GeometrySet &geometry_set,
dst_points_num += count * points_by_curve[index].size();
});
if (dst_points_num == 0) {
geometry_set.remove_geometry_during_modify();
return;
}
curve_offset_data.last() = dst_curves_num;
point_offset_data.last() = dst_points_num;

View File

@ -995,7 +995,7 @@ blender::Span<NodeSimulationItem> NodeGeometrySimulationOutput::items_span() con
return blender::Span<NodeSimulationItem>(items, items_num);
}
blender::MutableSpan<NodeSimulationItem> NodeGeometrySimulationOutput::items_span_for_write()
blender::MutableSpan<NodeSimulationItem> NodeGeometrySimulationOutput::items_span()
{
return blender::MutableSpan<NodeSimulationItem>(items, items_num);
}
@ -1077,7 +1077,7 @@ void NOD_geometry_simulation_output_set_active_item(NodeGeometrySimulationOutput
NodeSimulationItem *NOD_geometry_simulation_output_find_item(NodeGeometrySimulationOutput *sim,
const char *name)
{
for (NodeSimulationItem &item : sim->items_span_for_write()) {
for (NodeSimulationItem &item : sim->items_span()) {
if (STREQ(item.name, name)) {
return &item;
}
@ -1164,7 +1164,7 @@ void NOD_geometry_simulation_output_remove_item(NodeGeometrySimulationOutput *si
void NOD_geometry_simulation_output_clear_items(NodeGeometrySimulationOutput *sim)
{
for (NodeSimulationItem &item : sim->items_span_for_write()) {
for (NodeSimulationItem &item : sim->items_span()) {
MEM_SAFE_FREE(item.name);
}
MEM_SAFE_FREE(sim->items);

View File

@ -15,12 +15,14 @@ DerivedNodeTree::DerivedNodeTree(const bNodeTree &btree)
/* Construct all possible contexts immediately. This is significantly cheaper than inlining all
* node groups. If it still becomes a performance issue in the future, contexts could be
* constructed lazily when they are needed. */
root_context_ = &this->construct_context_recursively(nullptr, nullptr, btree);
root_context_ = &this->construct_context_recursively(
nullptr, nullptr, btree, NODE_INSTANCE_KEY_BASE);
}
DTreeContext &DerivedNodeTree::construct_context_recursively(DTreeContext *parent_context,
const bNode *parent_node,
const bNodeTree &btree)
const bNodeTree &btree,
const bNodeInstanceKey instance_key)
{
btree.ensure_topology_cache();
DTreeContext &context = *allocator_.construct<DTreeContext>().release();
@ -28,13 +30,16 @@ DTreeContext &DerivedNodeTree::construct_context_recursively(DTreeContext *paren
context.parent_node_ = parent_node;
context.derived_tree_ = this;
context.btree_ = &btree;
context.instance_key_ = instance_key;
used_btrees_.add(context.btree_);
for (const bNode *bnode : context.btree_->all_nodes()) {
if (bnode->is_group()) {
bNodeTree *child_btree = reinterpret_cast<bNodeTree *>(bnode->id);
if (child_btree != nullptr) {
DTreeContext &child = this->construct_context_recursively(&context, bnode, *child_btree);
const bNodeInstanceKey child_key = BKE_node_instance_key(instance_key, &btree, bnode);
DTreeContext &child = this->construct_context_recursively(
&context, bnode, *child_btree, child_key);
context.children_.add_new(bnode, &child);
}
}
@ -93,6 +98,11 @@ void DerivedNodeTree::foreach_node_in_context_recursive(const DTreeContext &cont
}
}
const bNodeInstanceKey DNode::instance_key() const
{
return BKE_node_instance_key(context()->instance_key(), &context()->btree(), bnode());
}
DOutputSocket DInputSocket::get_corresponding_group_node_output() const
{
BLI_assert(*this);
@ -299,6 +309,51 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn,
}
}
/* Find the active context from the given context and its descendants contexts. The active context
* is the one whose node instance key matches the active_viewer_key stored in the root node tree.
* The instance key of each context is computed by calling BKE_node_instance_key given the key of
* the parent as well as the group node making the context. */
static const DTreeContext *find_active_context_recursive(const DTreeContext *context)
{
const bNodeInstanceKey key = context->instance_key();
/* The instance key of the given context matches the active viewer instance key, so this is the
* active context, return it. */
if (key.value == context->derived_tree().root_context().btree().active_viewer_key.value) {
return context;
}
/* For each of the group nodes, compute their instance key and contexts and call this function
* recursively. */
for (const bNode *group_node : context->btree().group_nodes()) {
const DTreeContext *child_context = context->child_context(*group_node);
const DTreeContext *found_context = find_active_context_recursive(child_context);
/* If the found context is null, that means neither the child context nor one of its descendant
* contexts is active. */
if (!found_context) {
continue;
}
/* Otherwise, we have found our active context, return it. */
return found_context;
}
/* Neither the given context nor one of its descendant contexts is active, so return null. */
return nullptr;
}
const DTreeContext &DerivedNodeTree::active_context() const
{
/* If the active viewer key is NODE_INSTANCE_KEY_NONE, that means it is not yet initialized and
* we return the root context in that case. See the find_active_context_recursive function. */
if (root_context().btree().active_viewer_key.value == NODE_INSTANCE_KEY_NONE.value) {
return root_context();
}
return *find_active_context_recursive(&root_context());
}
/* Each nested node group gets its own cluster. Just as node groups, clusters can be nested. */
static dot::Cluster *get_dot_cluster_for_context(
dot::DirectedGraph &digraph,

View File

@ -182,9 +182,11 @@ bool id_property_type_matches_socket(const bNodeSocket &socket, const IDProperty
return property.type == IDP_INT;
case SOCK_VECTOR:
case SOCK_ROTATION:
return property.type == IDP_ARRAY && property.subtype == IDP_FLOAT && property.len == 3;
return property.type == IDP_ARRAY && ELEM(property.subtype, IDP_INT, IDP_FLOAT, IDP_FLOAT) &&
property.len == 3;
case SOCK_RGBA:
return property.type == IDP_ARRAY && property.subtype == IDP_FLOAT && property.len == 4;
return property.type == IDP_ARRAY &&
ELEM(property.subtype, IDP_INT, IDP_FLOAT, IDP_DOUBLE) && property.len == 4;
case SOCK_BOOLEAN:
return property.type == IDP_BOOLEAN;
case SOCK_STRING:
@ -222,12 +224,35 @@ static void init_socket_cpp_value_from_property(const IDProperty &property,
break;
}
case SOCK_VECTOR: {
float3 value = (const float *)IDP_Array(&property);
const void *property_array = IDP_Array(&property);
float3 value;
if (property.subtype == IDP_FLOAT) {
value = float3(static_cast<const float *>(property_array));
}
else if (property.subtype == IDP_INT) {
value = float3(int3(static_cast<const int *>(property_array)));
}
else {
BLI_assert(property.subtype == IDP_DOUBLE);
value = float3(double3(static_cast<const double *>(property_array)));
}
new (r_value) fn::ValueOrField<float3>(value);
break;
}
case SOCK_RGBA: {
ColorGeometry4f value = (const float *)IDP_Array(&property);
const void *property_array = IDP_Array(&property);
float4 vec;
if (property.subtype == IDP_FLOAT) {
vec = float4(static_cast<const float *>(property_array));
}
else if (property.subtype == IDP_INT) {
vec = float4(int4(static_cast<const int *>(property_array)));
}
else {
BLI_assert(property.subtype == IDP_DOUBLE);
vec = float4(double4(static_cast<const double *>(property_array)));
}
ColorGeometry4f value(vec);
new (r_value) fn::ValueOrField<ColorGeometry4f>(value);
break;
}
@ -237,8 +262,19 @@ static void init_socket_cpp_value_from_property(const IDProperty &property,
break;
}
case SOCK_ROTATION: {
const math::EulerXYZ euler_value = math::EulerXYZ(
float3(static_cast<const float *>(IDP_Array(&property))));
const void *property_array = IDP_Array(&property);
float3 vec;
if (property.subtype == IDP_FLOAT) {
vec = float3(static_cast<const float *>(property_array));
}
else if (property.subtype == IDP_INT) {
vec = float3(int3(static_cast<const int *>(property_array)));
}
else {
BLI_assert(property.subtype == IDP_DOUBLE);
vec = float3(double3(static_cast<const double *>(property_array)));
}
const math::EulerXYZ euler_value = math::EulerXYZ(vec);
new (r_value) fn::ValueOrField<math::Quaternion>(math::to_quaternion(euler_value));
break;
}

View File

@ -222,8 +222,8 @@ void RE_FreeAllPersistentData(void);
*/
void RE_FreePersistentData(const struct Scene *scene);
/*
* Free cached GPU textures to reduce memory usage. Before rendering all are cleard
/**
* Free cached GPU textures to reduce memory usage. Before rendering all are cleared
* and on UI changes when detected they are no longer used.
*/
void RE_FreeGPUTextureCaches(const bool only_unused);

View File

@ -99,6 +99,11 @@ class Context : public realtime_compositor::Context {
GPU_TEXTURE_FREE_SAFE(viewer_output_texture_);
}
const Scene &get_scene() const override
{
return scene_;
}
const bNodeTree &get_node_tree() const override
{
return node_tree_;

View File

@ -2513,7 +2513,7 @@ bool RE_ReadRenderResult(Scene *scene, Scene *scenode)
void RE_layer_load_from_file(
RenderLayer *layer, ReportList *reports, const char *filepath, int x, int y)
{
/* First try loading multilayer EXR. */
/* First try loading multi-layer EXR. */
if (render_result_exr_file_read_path(nullptr, layer, reports, filepath)) {
return;
}
@ -2522,7 +2522,7 @@ void RE_layer_load_from_file(
ImBuf *ibuf = IMB_loadiffname(filepath, IB_rect, nullptr);
RenderPass *rpass = nullptr;
/* multiview: since the API takes no 'view', we use the first combined pass found */
/* multi-view: since the API takes no 'view', we use the first combined pass found */
for (rpass = static_cast<RenderPass *>(layer->passes.first); rpass; rpass = rpass->next) {
if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) {
break;

View File

@ -47,6 +47,12 @@
static ThreadMutex sample_mutex = PTHREAD_MUTEX_INITIALIZER;
enum {
POINT_DATA_VEL = 1 << 0,
POINT_DATA_LIFE = 1 << 1,
POINT_DATA_COLOR = 1 << 2,
};
static int point_data_used(PointDensity *pd)
{
int pd_bitflag = 0;

View File

@ -517,7 +517,8 @@ static int voronoiTex(const Tex *tex, const float texvec[3], TexResult *texres)
BLI_noise_voronoi(texvec[0], texvec[1], texvec[2], da, pa, tex->vn_mexp, tex->vn_distm);
texres->tin = sc * fabsf(dot_v4v4(&tex->vn_w1, da));
if (tex->vn_coltype) {
const bool is_color = ELEM(tex->vn_coltype, TEX_COL1, TEX_COL2, TEX_COL3);
if (is_color) {
float ca[3]; /* cell color */
BLI_noise_cell_v3(pa[0], pa[1], pa[2], ca);
texres->trgba[0] = aw1 * ca[0];
@ -535,12 +536,12 @@ static int voronoiTex(const Tex *tex, const float texvec[3], TexResult *texres)
texres->trgba[0] += aw4 * ca[0];
texres->trgba[1] += aw4 * ca[1];
texres->trgba[2] += aw4 * ca[2];
if (tex->vn_coltype >= 2) {
if (ELEM(tex->vn_coltype, TEX_COL2, TEX_COL3)) {
float t1 = (da[1] - da[0]) * 10;
if (t1 > 1) {
t1 = 1;
}
if (tex->vn_coltype == 3) {
if (tex->vn_coltype == TEX_COL3) {
t1 *= texres->tin;
}
else {
@ -557,7 +558,7 @@ static int voronoiTex(const Tex *tex, const float texvec[3], TexResult *texres)
}
}
if (tex->vn_coltype) {
if (is_color) {
BRICONTRGB;
texres->trgba[3] = 1.0;
return (rv | TEX_RGB);