Merge branch 'master' into sculpt-dev

This commit is contained in:
Pablo Dobarro 2021-03-27 21:27:41 +01:00
commit 0bf2a1f8fe
190 changed files with 3275 additions and 1320 deletions

3
.gitignore vendored
View File

@ -46,3 +46,6 @@ Desktop.ini
# smoke simulation noise tile (generated)
waveletNoiseTile.bin
# testing environment
/Testing

View File

@ -1235,6 +1235,7 @@ if(WITH_OPENMP)
string(APPEND CMAKE_C_FLAGS " ${OpenMP_C_FLAGS}")
string(APPEND CMAKE_CXX_FLAGS " ${OpenMP_CXX_FLAGS}")
string(APPEND CMAKE_EXE_LINKER_FLAGS " ${OpenMP_LINKER_FLAGS}")
string(APPEND CMAKE_MODULE_LINKER_FLAGS " ${OpenMP_LINKER_FLAGS}")
else()
# Typically avoid adding flags as defines but we can't
# pass OpenMP flags to the linker for static builds, meaning

View File

@ -146,7 +146,7 @@ if(WITH_PYTHON)
set(PYTHON_INCLUDE_DIR "${_py_framework}/include/python${PYTHON_VERSION}")
set(PYTHON_EXECUTABLE "${_py_framework}/bin/python${PYTHON_VERSION}")
set(PYTHON_LIBPATH "${_py_framework}/lib/python${PYTHON_VERSION}/config-${PYTHON_VERSION}")
set(PYTHON_LIBPATH "${_py_framework}/lib/python${PYTHON_VERSION}/")
# set(PYTHON_LIBRARY python${PYTHON_VERSION})
# set(PYTHON_LINKFLAGS "-u _PyMac_Error -framework Python") # won't build with this enabled

View File

@ -375,7 +375,7 @@ static void attr_create_generic(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool
case BL::Attribute::domain_POINT:
element = ATTR_ELEMENT_VERTEX;
break;
case BL::Attribute::domain_POLYGON:
case BL::Attribute::domain_FACE:
element = ATTR_ELEMENT_FACE;
break;
default:

View File

@ -242,12 +242,15 @@ ccl_device float3 svm_math_blackbody_color(float t)
return make_float3(4.70366907f, 0.0f, 0.0f);
}
/* Manually align for readability. */
/* clang-format off */
int i = (t >= 6365.0f) ? 5 :
(t >= 3315.0f) ? 4 :
(t >= 1902.0f) ? 3 :
(t >= 1449.0f) ? 2 :
(t >= 1167.0f) ? 1 :
0;
/* clang-format on */
ccl_constant float *r = blackbody_table_r[i];
ccl_constant float *g = blackbody_table_g[i];

View File

@ -1584,7 +1584,6 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
dscene->tri_vnormal.tag_realloc();
dscene->tri_vindex.tag_realloc();
dscene->tri_patch.tag_realloc();
dscene->tri_vnormal.tag_realloc();
dscene->tri_patch_uv.tag_realloc();
dscene->tri_shader.tag_realloc();
dscene->patches.tag_realloc();

View File

@ -153,10 +153,6 @@ void Object::update_motion()
void Object::compute_bounds(bool motion_blur)
{
if (!is_modified() && !geometry->is_modified()) {
return;
}
BoundBox mbounds = geometry->bounds;
if (motion_blur && use_motion()) {

View File

@ -24,7 +24,8 @@
#pragma once
/*
/**
* \code{.py}
* import bpy
* import textwrap
*
@ -42,6 +43,7 @@
* print("%d,%d," % (w, h))
* text = ", ".join(["0x%x" % p for p in pixels])
* print(textwrap.fill(text, width=120), end=",\n")
* \endcode
*/
/**

View File

@ -533,11 +533,18 @@ GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state)
wp.showCmd = SW_SHOWMAXIMIZED;
wp.ptMaxPosition.x = 0;
wp.ptMaxPosition.y = 0;
style &= ~WS_CAPTION;
style &= ~(WS_CAPTION | WS_MAXIMIZE);
break;
case GHOST_kWindowStateNormal:
default:
wp.showCmd = SW_SHOWNORMAL;
if (curstate == GHOST_kWindowStateFullScreen &&
m_normal_state == GHOST_kWindowStateMaximized) {
wp.showCmd = SW_SHOWMAXIMIZED;
m_normal_state = GHOST_kWindowStateNormal;
}
else {
wp.showCmd = SW_SHOWNORMAL;
}
break;
}
::SetWindowLongPtr(m_hWnd, GWL_STYLE, style);

View File

@ -349,6 +349,10 @@ def enable(module_name, *, default_set=False, persistent=False, handle_error=Non
# 1) try import
try:
mod = __import__(module_name)
if mod.__file__ is None:
# This can happen when the addon has been removed but there are
# residual `.pyc` files left behind.
raise ImportError(name=module_name)
mod.__time__ = os.path.getmtime(mod.__file__)
mod.__addon_enabled__ = False
except Exception as ex:

View File

@ -1694,6 +1694,7 @@ def km_image(params):
("image.view_all", {"type": 'HOME', "value": 'PRESS', "shift": True},
{"properties": [("fit_view", True)]}),
("image.view_selected", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None),
("image.view_cursor_center", {"type": 'C', "value": 'PRESS', "shift": True}, None),
("image.view_pan", {"type": 'MIDDLEMOUSE', "value": 'PRESS'}, None),
("image.view_pan", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "shift": True}, None),
("image.view_pan", {"type": 'TRACKPADPAN', "value": 'ANY'}, None),

View File

@ -355,7 +355,8 @@ class UpdateAnimatedTransformConstraint(Operator):
use_convert_to_radians: BoolProperty(
name="Convert to Radians",
description="Convert fcurves/drivers affecting rotations to radians (Warning: use this only once!)",
description="Convert f-curves/drivers affecting rotations to radians.\n"
"Warning: Use this only once",
default=True,
)
@ -430,22 +431,9 @@ class UpdateAnimatedTransformConstraint(Operator):
return {'FINISHED'}
class ANIM_OT_show_group_colors_deprecated(Operator):
"""This option moved to Preferences > Animation"""
bl_idname = "anim.show_group_colors_deprecated"
bl_label = "Show Group Colors"
bl_options = {'REGISTER'}
@classmethod
def poll(cls, _context):
return False
classes = (
ANIM_OT_keying_set_export,
NLA_OT_bake,
ClearUselessActions,
UpdateAnimatedTransformConstraint,
ANIM_OT_show_group_colors_deprecated,
)

View File

@ -74,10 +74,6 @@ class PHYSICS_PT_add(PhysicButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
row = layout.row(align=True)
row.alignment = 'LEFT'
row.label(text="Enable physics for:")
flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
obj = context.object

View File

@ -348,8 +348,6 @@ class DOPESHEET_MT_view(Menu):
col.active = context.space_data.mode != 'SHAPEKEY'
col.prop(st, "show_sliders")
if bpy.app.version < (2, 93):
layout.operator("anim.show_group_colors_deprecated", icon='CHECKBOX_HLT')
layout.prop(st, "show_interpolation")
layout.prop(st, "show_extremes")
layout.prop(st, "use_auto_merge_keyframes")

View File

@ -18,7 +18,6 @@
# <pep8 compliant>
import bpy
from bpy.types import Header, Menu, Panel
from bl_ui.space_dopesheet import (
DopesheetFilterPopoverBase,
@ -120,10 +119,6 @@ class GRAPH_MT_view(Menu):
layout.prop(st, "use_realtime_update")
layout.prop(st, "show_cursor")
layout.prop(st, "show_sliders")
if bpy.app.version < (2, 93):
layout.operator("anim.show_group_colors_deprecated", icon='CHECKBOX_HLT')
layout.prop(st, "use_auto_merge_keyframes")
if st.mode != 'DRIVERS':

View File

@ -481,7 +481,7 @@ class NODE_MT_context_menu(Menu):
class NODE_PT_active_node_generic(Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
bl_category = "Item"
bl_category = "Node"
bl_label = "Node"
@classmethod
@ -499,7 +499,7 @@ class NODE_PT_active_node_generic(Panel):
class NODE_PT_active_node_color(Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
bl_category = "Item"
bl_category = "Node"
bl_label = "Color"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = 'NODE_PT_active_node_generic'
@ -529,7 +529,7 @@ class NODE_PT_active_node_color(Panel):
class NODE_PT_active_node_properties(Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
bl_category = "Item"
bl_category = "Node"
bl_label = "Properties"
bl_options = {'DEFAULT_CLOSED'}
@ -570,7 +570,7 @@ class NODE_PT_active_node_properties(Panel):
class NODE_PT_texture_mapping(Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
bl_category = "Item"
bl_category = "Node"
bl_label = "Texture Mapping"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}

View File

@ -484,6 +484,7 @@ geometry_node_categories = [
GeometryNodeCategory("GEO_ATTRIBUTE", "Attribute", items=[
NodeItem("GeometryNodeAttributeRandomize"),
NodeItem("GeometryNodeAttributeMath"),
NodeItem("GeometryNodeAttributeClamp"),
NodeItem("GeometryNodeAttributeCompare"),
NodeItem("GeometryNodeAttributeConvert"),
NodeItem("GeometryNodeAttributeFill"),
@ -495,6 +496,7 @@ geometry_node_categories = [
NodeItem("GeometryNodeAttributeCombineXYZ"),
NodeItem("GeometryNodeAttributeSeparateXYZ"),
NodeItem("GeometryNodeAttributeRemove"),
NodeItem("GeometryNodeAttributeMapRange"),
]),
GeometryNodeCategory("GEO_COLOR", "Color", items=[
NodeItem("ShaderNodeValToRGB"),
@ -520,7 +522,16 @@ geometry_node_categories = [
NodeItem("GeometryNodeEdgeSplit"),
NodeItem("GeometryNodeSubdivisionSurface"),
NodeItem("GeometryNodeSubdivide"),
]),
GeometryNodeCategory("GEO_PRIMITIVES", "Mesh Primitives", items=[
NodeItem("GeometryNodeMeshCircle"),
NodeItem("GeometryNodeMeshCone"),
NodeItem("GeometryNodeMeshCube"),
NodeItem("GeometryNodeMeshCylinder"),
NodeItem("GeometryNodeMeshGrid"),
NodeItem("GeometryNodeMeshIcoSphere"),
NodeItem("GeometryNodeMeshLine"),
NodeItem("GeometryNodeMeshUVSphere"),
]),
GeometryNodeCategory("GEO_POINT", "Point", items=[
NodeItem("GeometryNodePointDistribute"),
@ -531,20 +542,6 @@ geometry_node_categories = [
NodeItem("GeometryNodeRotatePoints"),
NodeItem("GeometryNodeAlignRotationToVector"),
]),
GeometryNodeCategory("GEO_VOLUME", "Volume", items=[
NodeItem("GeometryNodePointsToVolume"),
NodeItem("GeometryNodeVolumeToMesh"),
]),
GeometryNodeCategory("GEO_PRIMITIVES", "Mesh Primitives", items=[
NodeItem("GeometryNodeMeshCube"),
NodeItem("GeometryNodeMeshCircle"),
NodeItem("GeometryNodeMeshUVSphere"),
NodeItem("GeometryNodeMeshIcoSphere"),
NodeItem("GeometryNodeMeshCylinder"),
NodeItem("GeometryNodeMeshCone"),
NodeItem("GeometryNodeMeshLine"),
NodeItem("GeometryNodeMeshPlane"),
]),
GeometryNodeCategory("GEO_UTILITIES", "Utilities", items=[
NodeItem("ShaderNodeMapRange"),
NodeItem("ShaderNodeClamp"),
@ -558,6 +555,10 @@ geometry_node_categories = [
NodeItem("ShaderNodeVectorMath"),
NodeItem("ShaderNodeVectorRotate"),
]),
GeometryNodeCategory("GEO_VOLUME", "Volume", items=[
NodeItem("GeometryNodePointsToVolume"),
NodeItem("GeometryNodeVolumeToMesh"),
]),
GeometryNodeCategory("GEO_GROUP", "Group", items=node_group_items),
GeometryNodeCategory("GEO_LAYOUT", "Layout", items=[
NodeItem("NodeFrame"),

View File

@ -0,0 +1,10 @@
shader basic_shader(
float in_float = 1.0,
color in_color = color(1.0, 1.0, 1.0),
output float out_float = 0.0,
output color out_color = color(0.0, 0.0, 0.0)
)
{
out_float = in_float * 2.0;
out_color = in_color * 2.0;
}

View File

@ -227,6 +227,9 @@ void BKE_pose_blend_read_data(struct BlendDataReader *reader, struct bPose *pose
void BKE_pose_blend_read_lib(struct BlendLibReader *reader, struct Object *ob, struct bPose *pose);
void BKE_pose_blend_read_expand(struct BlendExpander *expander, struct bPose *pose);
/* action_mirror.c */
void BKE_action_flip_with_pose(struct bAction *act, struct Object *ob_arm);
#ifdef __cplusplus
};
#endif

View File

@ -39,12 +39,12 @@ struct ReportList;
/* Attribute.domain */
typedef enum AttributeDomain {
ATTR_DOMAIN_AUTO = -1, /* Use for nodes to choose automatically based on other data. */
ATTR_DOMAIN_POINT = 0, /* Mesh, Hair or PointCloud Point */
ATTR_DOMAIN_EDGE = 1, /* Mesh Edge */
ATTR_DOMAIN_CORNER = 2, /* Mesh Corner */
ATTR_DOMAIN_POLYGON = 3, /* Mesh Polygon */
ATTR_DOMAIN_CURVE = 4, /* Hair Curve */
ATTR_DOMAIN_AUTO = -1, /* Use for nodes to choose automatically based on other data. */
ATTR_DOMAIN_POINT = 0, /* Mesh, Hair or PointCloud Point */
ATTR_DOMAIN_EDGE = 1, /* Mesh Edge */
ATTR_DOMAIN_CORNER = 2, /* Mesh Corner */
ATTR_DOMAIN_FACE = 3, /* Mesh Face */
ATTR_DOMAIN_CURVE = 4, /* Hair Curve */
ATTR_DOMAIN_NUM
} AttributeDomain;

View File

@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 14
#define BLENDER_FILE_SUBVERSION 15
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file

View File

@ -232,6 +232,19 @@ int BKE_fcurve_bezt_binarysearch_index(struct BezTriple array[],
int arraylen,
bool *r_replace);
/* fcurve_cache.c */
/* Cached f-curve look-ups, use when this needs to be done many times. */
struct FCurvePathCache;
struct FCurvePathCache *BKE_fcurve_pathcache_create(ListBase *list);
void BKE_fcurve_pathcache_destroy(struct FCurvePathCache *fcache);
struct FCurve *BKE_fcurve_pathcache_find(struct FCurvePathCache *fcache,
const char rna_path[],
const int array_index);
int BKE_fcurve_pathcache_find_array(struct FCurvePathCache *fcache,
const char *rna_path,
struct FCurve **fcurve_result,
int fcurve_result_len);
/* get the time extents for F-Curve */
bool BKE_fcurve_calc_range(
struct FCurve *fcu, float *min, float *max, const bool do_sel_only, const bool do_min_length);
@ -245,6 +258,14 @@ bool BKE_fcurve_calc_bounds(struct FCurve *fcu,
const bool do_sel_only,
const bool include_handles);
float *BKE_fcurves_calc_keyed_frames_ex(struct FCurve **fcurve_array,
const int fcurve_array_len,
const float interval,
int *r_frames_len);
float *BKE_fcurves_calc_keyed_frames(struct FCurve **fcurve_array,
const int fcurve_array_len,
int *r_frames_len);
void BKE_fcurve_active_keyframe_set(struct FCurve *fcu, const struct BezTriple *active_bezt);
int BKE_fcurve_active_keyframe_index(const struct FCurve *fcu);

View File

@ -39,7 +39,8 @@ struct GeometryInstanceGroup {
Vector<float4x4> transforms;
};
Vector<GeometryInstanceGroup> geometry_set_gather_instances(const GeometrySet &geometry_set);
void geometry_set_gather_instances(const GeometrySet &geometry_set,
Vector<GeometryInstanceGroup> &r_instance_groups);
GeometrySet geometry_set_realize_mesh_for_modifier(const GeometrySet &geometry_set);
GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set);

View File

@ -483,14 +483,14 @@ void ntreeBlendReadExpand(struct BlendExpander *expander, struct bNodeTree *ntre
/** \name Node Tree Interface
* \{ */
struct bNodeSocket *ntreeFindSocketInterface(struct bNodeTree *ntree,
int in_out,
eNodeSocketInOut in_out,
const char *identifier);
struct bNodeSocket *ntreeAddSocketInterface(struct bNodeTree *ntree,
int in_out,
eNodeSocketInOut in_out,
const char *idname,
const char *name);
struct bNodeSocket *ntreeInsertSocketInterface(struct bNodeTree *ntree,
int in_out,
eNodeSocketInOut in_out,
const char *idname,
struct bNodeSocket *next_sock,
const char *name);
@ -556,30 +556,32 @@ const char *nodeStaticSocketInterfaceType(int type, int subtype);
} \
((void)0)
struct bNodeSocket *nodeFindSocket(const struct bNode *node, int in_out, const char *identifier);
struct bNodeSocket *nodeFindSocket(const struct bNode *node,
eNodeSocketInOut in_out,
const char *identifier);
struct bNodeSocket *nodeAddSocket(struct bNodeTree *ntree,
struct bNode *node,
int in_out,
eNodeSocketInOut in_out,
const char *idname,
const char *identifier,
const char *name);
struct bNodeSocket *nodeInsertSocket(struct bNodeTree *ntree,
struct bNode *node,
int in_out,
eNodeSocketInOut in_out,
const char *idname,
struct bNodeSocket *next_sock,
const char *identifier,
const char *name);
struct bNodeSocket *nodeAddStaticSocket(struct bNodeTree *ntree,
struct bNode *node,
int in_out,
eNodeSocketInOut in_out,
int type,
int subtype,
const char *identifier,
const char *name);
struct bNodeSocket *nodeInsertStaticSocket(struct bNodeTree *ntree,
struct bNode *node,
int in_out,
eNodeSocketInOut in_out,
int type,
int subtype,
struct bNodeSocket *next_sock,
@ -1393,7 +1395,9 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE 1036
#define GEO_NODE_MESH_PRIMITIVE_CONE 1037
#define GEO_NODE_MESH_PRIMITIVE_LINE 1038
#define GEO_NODE_MESH_PRIMITIVE_PLANE 1039
#define GEO_NODE_MESH_PRIMITIVE_GRID 1039
#define GEO_NODE_ATTRIBUTE_MAP_RANGE 1040
#define GEO_NODE_ATTRIBUTE_CLAMP 1041
/** \} */

View File

@ -58,9 +58,7 @@ class NodeTreeEvaluationContext {
uint64_t hash() const
{
const uint64_t hash1 = blender::DefaultHash<std::string>{}(object_name_);
const uint64_t hash2 = BLI_session_uuid_hash_uint64(&modifier_session_uuid_);
return hash1 ^ (hash2 * 33); /* Copied from DefaultHash for std::pair. */
return blender::get_default_hash_2(object_name_, modifier_session_uuid_);
}
friend bool operator==(const NodeTreeEvaluationContext &a, const NodeTreeEvaluationContext &b)

View File

@ -69,6 +69,7 @@ set(SRC
intern/CCGSubSurf_util.c
intern/DerivedMesh.cc
intern/action.c
intern/action_mirror.c
intern/addon.c
intern/anim_data.c
intern/anim_path.c
@ -126,6 +127,7 @@ set(SRC
intern/editmesh_tangent.c
intern/effect.c
intern/fcurve.c
intern/fcurve_cache.c
intern/fcurve_driver.c
intern/fluid.c
intern/fmodifier.c
@ -385,6 +387,7 @@ set(SRC
BKE_multires.h
BKE_nla.h
BKE_node.h
BKE_node_ui_storage.hh
BKE_object.h
BKE_object_deform.h
BKE_object_facemap.h
@ -434,10 +437,10 @@ set(SRC
nla_private.h
particle_private.h
tracking_private.h
intern/attribute_access_intern.hh
intern/CCGSubSurf.h
intern/CCGSubSurf_inline.h
intern/CCGSubSurf_intern.h
intern/attribute_access_intern.hh
intern/data_transfer_intern.h
intern/lib_intern.h
intern/multires_inline.h
@ -742,7 +745,7 @@ if(WITH_GMP)
list(APPEND INC_SYS
${GMP_INCLUDE_DIRS}
)
endif()
endif()
# # Warnings as errors, this is too strict!
# if(MSVC)

View File

@ -0,0 +1,457 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup bke
*
* Mirror/Symmetry functions applying to actions.
*/
#include <math.h>
#include <string.h>
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_object_types.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_fcurve.h"
#include "DEG_depsgraph.h"
/* -------------------------------------------------------------------- */
/** \name Flip the Action (Armature/Pose Objects)
*
* This flips the action using the rest pose (not the evaluated pose).
*
* Details:
*
* - Key-frames are modified in-place, creating new key-frames is not yet supported.
* That could be useful if a user for example only has 2x rotation channels set.
* In practice users typically keyframe all rotation channels or none.
*
* - F-curve modifiers are disabled for evaluation,
* so the values written back to the keyframes don't include modifier offsets.
*
* - Sub-frame key-frames aren't supported,
* this could be added if needed without much trouble.
*
* - F-curves must have a #FCurve.bezt array (sampled curves aren't supported).
* \{ */
/**
* This structure is created for each pose channels F-curve,
* an action be evaluated and stored in `fcurve_eval`,
* with the mirrored values written into `bezt_array`.
*
* Store F-curve evaluated values, constructed with a sorted array of rounded keyed-frames,
* passed to #action_flip_pchan_cache_init.
*/
struct FCurve_KeyCache {
/**
* When NULL, ignore this channel.
*/
FCurve *fcurve;
/**
* Cached evaluated F-curve values (without modifiers).
*/
float *fcurve_eval;
/**
* Cached #FCurve.bezt values, NULL when no key-frame exists on this frame.
*
* \note The case where two keyframes round to the same frame isn't supported.
* In this case only the first will be used.
*/
BezTriple **bezt_array;
};
/**
* Assign `fkc` path, using a `path` lookup for a single value.
*/
static void action_flip_pchan_cache_fcurve_assign_value(struct FCurve_KeyCache *fkc,
int index,
const char *path,
struct FCurvePathCache *fcache)
{
FCurve *fcu = BKE_fcurve_pathcache_find(fcache, path, index);
if (fcu && fcu->bezt) {
fkc->fcurve = fcu;
}
}
/**
* Assign #FCurve_KeyCache.fcurve path, using a `path` lookup for an array.
*/
static void action_flip_pchan_cache_fcurve_assign_array(struct FCurve_KeyCache *fkc,
int fkc_len,
const char *path,
struct FCurvePathCache *fcache)
{
FCurve **fcurves = alloca(sizeof(*fcurves) * fkc_len);
if (BKE_fcurve_pathcache_find_array(fcache, path, fcurves, fkc_len)) {
for (int i = 0; i < fkc_len; i++) {
if (fcurves[i] && fcurves[i]->bezt) {
fkc[i].fcurve = fcurves[i];
}
}
}
}
/**
* Fill in pose channel cache for each frame in `keyed_frames`.
*
* \param keyed_frames: An array of keyed_frames to evaluate,
* note that each frame is rounded to the nearest int.
* \param keyed_frames_len: The length of the `keyed_frames` array.
*/
static void action_flip_pchan_cache_init(struct FCurve_KeyCache *fkc,
const float *keyed_frames,
int keyed_frames_len)
{
BLI_assert(fkc->fcurve != NULL);
/* Cache the F-curve values for `keyed_frames`. */
const int fcurve_flag = fkc->fcurve->flag;
fkc->fcurve->flag |= FCURVE_MOD_OFF;
fkc->fcurve_eval = MEM_mallocN(sizeof(float) * keyed_frames_len, __func__);
for (int frame_index = 0; frame_index < keyed_frames_len; frame_index++) {
const float evaltime = keyed_frames[frame_index];
fkc->fcurve_eval[frame_index] = evaluate_fcurve_only_curve(fkc->fcurve, evaltime);
}
fkc->fcurve->flag = fcurve_flag;
/* Cache the #BezTriple for `keyed_frames`, or leave as NULL. */
fkc->bezt_array = MEM_mallocN(sizeof(*fkc->bezt_array) * keyed_frames_len, __func__);
BezTriple *bezt = fkc->fcurve->bezt;
BezTriple *bezt_end = fkc->fcurve->bezt + fkc->fcurve->totvert;
int frame_index = 0;
while (frame_index < keyed_frames_len) {
const float evaltime = keyed_frames[frame_index];
const float bezt_time = roundf(bezt->vec[1][0]);
if (bezt_time > evaltime) {
fkc->bezt_array[frame_index++] = NULL;
}
else {
if (bezt_time == evaltime) {
fkc->bezt_array[frame_index++] = bezt;
}
bezt++;
if (bezt == bezt_end) {
break;
}
}
}
/* Clear remaining unset keyed_frames (if-any). */
while (frame_index < keyed_frames_len) {
fkc->bezt_array[frame_index++] = NULL;
}
}
/**
*/
static void action_flip_pchan(Object *ob_arm,
const bPoseChannel *pchan,
struct FCurvePathCache *fcache)
{
/* Begin F-Curve pose channel value extraction. */
/* Use a fixed buffer size as it's known this can only be at most:
* `pose.bones["{MAXBONENAME}"].rotation_quaternion`. */
char path_xform[256];
char pchan_name_esc[sizeof(((bActionChannel *)NULL)->name) * 2];
BLI_str_escape(pchan_name_esc, pchan->name, sizeof(pchan_name_esc));
const int path_xform_prefix_len = SNPRINTF(path_xform, "pose.bones[\"%s\"]", pchan_name_esc);
char *path_xform_suffix = path_xform + path_xform_prefix_len;
const int path_xform_suffix_len = sizeof(path_xform) - path_xform_prefix_len;
/* Lookup and assign all available #FCurve channels,
* unavailable channels are left NULL. */
/**
* Structure to store transformation F-curves corresponding to a pose bones transformation.
* Match struct member names from #bPoseChannel so macros avoid repetition.
*
* \note There is no need to read values unless they influence the 4x4 transform matrix,
* and no need to write values back unless they would be changed by a modified matrix.
* So `rotmode` needs to be read, but doesn't need to be written back to.
*
* Most bendy-bone settings don't need to be included either, flipping their RNA paths is enough.
* Although the X/Y settings could make sense to transform, in practice it would only
* work well if the rotation happened to swap X/Y alignment, leave this for now.
*/
struct {
struct FCurve_KeyCache loc[3], eul[3], quat[4], rotAxis[3], rotAngle, size[3], rotmode;
} fkc_pchan = {{{NULL}}};
#define FCURVE_ASSIGN_VALUE(id, path_test_suffix, index) \
BLI_strncpy(path_xform_suffix, path_test_suffix, path_xform_suffix_len); \
action_flip_pchan_cache_fcurve_assign_value(&fkc_pchan.id, index, path_xform, fcache)
#define FCURVE_ASSIGN_ARRAY(id, path_test_suffix) \
BLI_strncpy(path_xform_suffix, path_test_suffix, path_xform_suffix_len); \
action_flip_pchan_cache_fcurve_assign_array( \
fkc_pchan.id, ARRAY_SIZE(fkc_pchan.id), path_xform, fcache)
FCURVE_ASSIGN_ARRAY(loc, ".location");
FCURVE_ASSIGN_ARRAY(eul, ".rotation_euler");
FCURVE_ASSIGN_ARRAY(quat, ".rotation_quaternion");
FCURVE_ASSIGN_ARRAY(rotAxis, ".rotation_axis_angle");
FCURVE_ASSIGN_VALUE(rotAngle, ".rotation_axis_angle", 3);
FCURVE_ASSIGN_ARRAY(size, ".scale");
FCURVE_ASSIGN_VALUE(rotmode, ".rotation_mode", 0);
#undef FCURVE_ASSIGN_VALUE
#undef FCURVE_ASSIGN_ARRAY
/* Array of F-curves, for convenient access. */
#define FCURVE_CHANNEL_LEN (sizeof(fkc_pchan) / sizeof(struct FCurve_KeyCache))
FCurve *fcurve_array[FCURVE_CHANNEL_LEN];
int fcurve_array_len = 0;
for (int chan = 0; chan < FCURVE_CHANNEL_LEN; chan++) {
struct FCurve_KeyCache *fkc = (struct FCurve_KeyCache *)(&fkc_pchan) + chan;
if (fkc->fcurve != NULL) {
fcurve_array[fcurve_array_len++] = fkc->fcurve;
}
}
/* If this pose has no transform channels, there is nothing to do. */
if (fcurve_array_len == 0) {
return;
}
/* Calculate an array of frames used by any of the key-frames in `fcurve_array`. */
int keyed_frames_len;
const float *keyed_frames = BKE_fcurves_calc_keyed_frames(
fcurve_array, fcurve_array_len, &keyed_frames_len);
/* Initialize the pose channel curve cache from the F-curve. */
for (int chan = 0; chan < FCURVE_CHANNEL_LEN; chan++) {
struct FCurve_KeyCache *fkc = (struct FCurve_KeyCache *)(&fkc_pchan) + chan;
if (fkc->fcurve == NULL) {
continue;
}
action_flip_pchan_cache_init(fkc, keyed_frames, keyed_frames_len);
}
/* X-axis flipping matrix. */
float flip_mtx[4][4];
unit_m4(flip_mtx);
flip_mtx[0][0] = -1;
bPoseChannel *pchan_flip = NULL;
char pchan_name_flip[MAXBONENAME];
BLI_string_flip_side_name(pchan_name_flip, pchan->name, false, sizeof(pchan_name_flip));
if (!STREQ(pchan_name_flip, pchan->name)) {
pchan_flip = BKE_pose_channel_find_name(ob_arm->pose, pchan_name_flip);
}
float arm_mat_inv[4][4];
invert_m4_m4(arm_mat_inv, pchan_flip ? pchan_flip->bone->arm_mat : pchan->bone->arm_mat);
/* Now flip the transformation & write it back to the F-curves in `fkc_pchan`. */
for (int frame_index = 0; frame_index < keyed_frames_len; frame_index++) {
/* Temporary pose channel to write values into,
* using the `fkc_pchan` values, falling back to the values in the pose channel. */
bPoseChannel pchan_temp = *pchan;
/* Load the values into the channel. */
#define READ_VALUE_FLT(id) \
if (fkc_pchan.id.fcurve_eval != NULL) { \
pchan_temp.id = fkc_pchan.id.fcurve_eval[frame_index]; \
} \
((void)0)
#define READ_VALUE_INT(id) \
if (fkc_pchan.id.fcurve_eval != NULL) { \
pchan_temp.id = floorf(fkc_pchan.id.fcurve_eval[frame_index] + 0.5f); \
} \
((void)0)
#define READ_ARRAY_FLT(id) \
for (int i = 0; i < ARRAY_SIZE(pchan_temp.id); i++) { \
READ_VALUE_FLT(id[i]); \
} \
((void)0)
READ_ARRAY_FLT(loc);
READ_ARRAY_FLT(eul);
READ_ARRAY_FLT(quat);
READ_ARRAY_FLT(rotAxis);
READ_VALUE_FLT(rotAngle);
READ_ARRAY_FLT(size);
READ_VALUE_INT(rotmode);
#undef READ_ARRAY_FLT
#undef READ_VALUE_FLT
#undef READ_VALUE_INT
float chan_mat[4][4];
BKE_pchan_to_mat4(&pchan_temp, chan_mat);
/* Move to the pose-space. */
mul_m4_m4m4(chan_mat, pchan->bone->arm_mat, chan_mat);
/* Flip the matrix. */
mul_m4_m4m4(chan_mat, chan_mat, flip_mtx);
mul_m4_m4m4(chan_mat, flip_mtx, chan_mat);
/* Move back to bone-space space, using the flipped bone if it exists. */
mul_m4_m4m4(chan_mat, arm_mat_inv, chan_mat);
BKE_pchan_apply_mat4(&pchan_temp, chan_mat, false);
/* Write the values back to the F-curves. */
#define WRITE_VALUE_FLT(id) \
if (fkc_pchan.id.fcurve_eval != NULL) { \
BezTriple *bezt = fkc_pchan.id.bezt_array[frame_index]; \
if (bezt != NULL) { \
const float delta = pchan_temp.id - bezt->vec[1][1]; \
bezt->vec[0][1] += delta; \
bezt->vec[1][1] += delta; \
bezt->vec[2][1] += delta; \
} \
} \
((void)0)
#define WRITE_ARRAY_FLT(id) \
for (int i = 0; i < ARRAY_SIZE(pchan_temp.id); i++) { \
WRITE_VALUE_FLT(id[i]); \
} \
((void)0)
/* Write the values back the the F-curves. */
WRITE_ARRAY_FLT(loc);
WRITE_ARRAY_FLT(eul);
WRITE_ARRAY_FLT(quat);
WRITE_ARRAY_FLT(rotAxis);
WRITE_VALUE_FLT(rotAngle);
WRITE_ARRAY_FLT(size);
/* No need to write back 'rotmode' as it can't be transformed. */
#undef WRITE_ARRAY_FLT
#undef WRITE_VALUE_FLT
}
/* Recalculate handles. */
for (int i = 0; i < fcurve_array_len; i++) {
calchandles_fcurve_ex(fcurve_array[i], 0);
}
MEM_freeN((void *)keyed_frames);
for (int chan = 0; chan < FCURVE_CHANNEL_LEN; chan++) {
struct FCurve_KeyCache *fkc = (struct FCurve_KeyCache *)(&fkc_pchan) + chan;
if (fkc->fcurve_eval) {
MEM_freeN(fkc->fcurve_eval);
}
if (fkc->bezt_array) {
MEM_freeN(fkc->bezt_array);
}
}
}
/**
* Swap all RNA paths left/right.
*/
static void action_flip_pchan_rna_paths(struct bAction *act)
{
const char *path_pose_prefix = "pose.bones[\"";
const int path_pose_prefix_len = strlen(path_pose_prefix);
/* Tag curves that have renamed f-curves. */
LISTBASE_FOREACH (bActionGroup *, agrp, &act->groups) {
agrp->flag &= ~AGRP_TEMP;
}
LISTBASE_FOREACH (FCurve *, fcu, &act->curves) {
if (!STRPREFIX(fcu->rna_path, path_pose_prefix)) {
continue;
}
const char *name_esc = fcu->rna_path + path_pose_prefix_len;
const char *name_esc_end = BLI_str_escape_find_quote(name_esc);
/* While unlikely, an RNA path could be malformed. */
if (UNLIKELY(name_esc_end == NULL)) {
continue;
}
char name[MAXBONENAME];
const size_t name_esc_len = (size_t)(name_esc_end - name_esc);
const size_t name_len = BLI_str_unescape(name, name_esc, name_esc_len);
/* While unlikely, data paths could be constructed that have longer names than
* are currently supported. */
if (UNLIKELY(name_len >= sizeof(name))) {
continue;
}
/* When the flipped name differs, perform the rename. */
char name_flip[MAXBONENAME];
BLI_string_flip_side_name(name_flip, name, false, sizeof(name_flip));
if (!STREQ(name_flip, name)) {
char name_flip_esc[MAXBONENAME * 2];
BLI_str_escape(name_flip_esc, name_flip, sizeof(name_flip_esc));
char *path_flip = BLI_sprintfN("pose.bones[\"%s%s", name_flip_esc, name_esc_end);
MEM_freeN(fcu->rna_path);
fcu->rna_path = path_flip;
if (fcu->grp != NULL) {
fcu->grp->flag |= AGRP_TEMP;
}
}
}
/* Rename tagged groups. */
LISTBASE_FOREACH (bActionGroup *, agrp, &act->groups) {
if ((agrp->flag & AGRP_TEMP) == 0) {
continue;
}
agrp->flag &= ~AGRP_TEMP;
char name_flip[MAXBONENAME];
BLI_string_flip_side_name(name_flip, agrp->name, false, sizeof(name_flip));
if (!STREQ(name_flip, agrp->name)) {
STRNCPY(agrp->name, name_flip);
}
}
}
void BKE_action_flip_with_pose(struct bAction *act, struct Object *ob_arm)
{
struct FCurvePathCache *fcache = BKE_fcurve_pathcache_create(&act->curves);
int i;
LISTBASE_FOREACH_INDEX (bPoseChannel *, pchan, &ob_arm->pose->chanbase, i) {
action_flip_pchan(ob_arm, pchan, fcache);
}
BKE_fcurve_pathcache_destroy(fcache);
action_flip_pchan_rna_paths(act);
DEG_id_tag_update(&act->id, ID_RECALC_COPY_ON_WRITE);
}
/** \} */

View File

@ -69,8 +69,8 @@ static void get_domains(ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
info[ATTR_DOMAIN_EDGE].length = mesh->totedge;
info[ATTR_DOMAIN_CORNER].customdata = &mesh->ldata;
info[ATTR_DOMAIN_CORNER].length = mesh->totloop;
info[ATTR_DOMAIN_POLYGON].customdata = &mesh->pdata;
info[ATTR_DOMAIN_POLYGON].length = mesh->totpoly;
info[ATTR_DOMAIN_FACE].customdata = &mesh->pdata;
info[ATTR_DOMAIN_FACE].length = mesh->totpoly;
break;
}
case ID_HA: {

View File

@ -331,7 +331,7 @@ static int attribute_domain_priority(const AttributeDomain domain)
case ATTR_DOMAIN_CURVE:
return 0;
#endif
case ATTR_DOMAIN_POLYGON:
case ATTR_DOMAIN_FACE:
return 1;
case ATTR_DOMAIN_EDGE:
return 2;
@ -893,7 +893,7 @@ ReadAttributePtr GeometryComponent::attribute_try_get_for_read(
return {};
}
if (attribute->domain() != domain) {
if (domain != ATTR_DOMAIN_AUTO && attribute->domain() != domain) {
attribute = this->attribute_try_adapt_domain(std::move(attribute), domain);
if (!attribute) {
return {};

View File

@ -400,6 +400,8 @@ static void setup_app_data(bContext *C,
bmain,
curscene,
bfd->cur_view_layer ? bfd->cur_view_layer : BKE_view_layer_default_view(curscene));
/* We need to rebuild some of the deleted override rules (for UI feedback purpose). */
BKE_lib_override_library_main_operations_create(bmain, true);
}
}

View File

@ -99,6 +99,7 @@ static void cache_file_blend_write(BlendWriter *writer, ID *id, const void *id_a
cache_file->handle_readers = NULL;
BLO_write_id_struct(writer, CacheFile, id_address, &cache_file->id);
BKE_id_blend_write(writer, &cache_file->id);
if (cache_file->adt) {
BKE_animdata_blend_write(writer, cache_file->adt);

View File

@ -425,6 +425,9 @@ static bool from_manifest(CryptomatteLayer &layer, blender::StringRefNull manife
}
const int quoted_hash_len = quoted_string_len_(ref);
if (quoted_hash_len < 2) {
return false;
}
const int hash_len = quoted_hash_len - 2;
CryptomatteHash hash = CryptomatteHash::from_hex_encoded(ref.substr(1, hash_len));
ref = ref.drop_prefix(quoted_hash_len);

View File

@ -35,7 +35,9 @@
#include "BLI_blenlib.h"
#include "BLI_easing.h"
#include "BLI_ghash.h"
#include "BLI_math.h"
#include "BLI_sort_utils.h"
#include "BKE_anim_data.h"
#include "BKE_animsys.h"
@ -290,6 +292,12 @@ FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_i
return NULL;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name FCurve Iteration
* \{ */
/* Quick way to loop over all fcurves of a given 'path'. */
FCurve *BKE_fcurve_iter_step(FCurve *fcu_iter, const char rna_path[])
{
@ -829,6 +837,56 @@ bool BKE_fcurve_calc_range(
return foundvert;
}
/**
* Return an array of keyed frames, rounded to `interval`.
*
* \param interval: Set to 1.0 to round to whole keyframes, 0.5 for in-between key-frames, etc.
*
* \note An interval of zero could be supported (this implies no rounding at all),
* however this risks very small differences in float values being treated as separate keyframes.
*/
float *BKE_fcurves_calc_keyed_frames_ex(FCurve **fcurve_array,
int fcurve_array_len,
const float interval,
int *r_frames_len)
{
/* Use `1e-3f` as the smallest possible value since these are converted to integers
* and we can be sure `MAXFRAME / 1e-3f < INT_MAX` as it's around half the size. */
const double interval_db = max_ff(interval, 1e-3f);
GSet *frames_unique = BLI_gset_int_new(__func__);
for (int fcurve_index = 0; fcurve_index < fcurve_array_len; fcurve_index++) {
const FCurve *fcu = fcurve_array[fcurve_index];
for (int i = 0; i < fcu->totvert; i++) {
const BezTriple *bezt = &fcu->bezt[i];
const double value = round((double)bezt->vec[1][0] / interval_db);
BLI_assert(value > INT_MIN && value < INT_MAX);
BLI_gset_add(frames_unique, POINTER_FROM_INT((int)value));
}
}
const size_t frames_len = BLI_gset_len(frames_unique);
float *frames = MEM_mallocN(sizeof(*frames) * frames_len, __func__);
GSetIterator gs_iter;
int i = 0;
GSET_ITER_INDEX (gs_iter, frames_unique, i) {
const int value = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter));
frames[i] = (double)value * interval_db;
}
BLI_gset_free(frames_unique, NULL);
qsort(frames, frames_len, sizeof(*frames), BLI_sortutil_cmp_float);
*r_frames_len = frames_len;
return frames;
}
float *BKE_fcurves_calc_keyed_frames(FCurve **fcurve_array,
int fcurve_array_len,
int *r_frames_len)
{
return BKE_fcurves_calc_keyed_frames_ex(fcurve_array, fcurve_array_len, 1.0f, r_frames_len);
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -0,0 +1,189 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup bke
*
* Cache F-Curve look-ups.
*/
#include <stdlib.h>
#include <string.h>
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BKE_fcurve.h"
/* -------------------------------------------------------------------- */
/** \name F-Curve Path Cache
*
* Cache for finding curves by RNA path & array index.
* \{ */
struct FCurvePathCache_Span {
/** Index in the #FCurvePathCache.fcurve_array indicating the start of the span. */
uint index;
/** Number of items in the span in #FCurvePathCache.fcurve_array that share an RNA path. */
uint len;
};
struct FCurvePathCache {
/** All curves sorted by (#FCurve.rna_path, #FCurve.array_index) */
FCurve **fcurve_array;
uint fcurve_array_len;
/** Storage for values of `span_from_rna_path`. */
struct FCurvePathCache_Span *span_table;
/** Map `FCurve.rna_path` to elements in #FCurvePathCache.span_table */
GHash *span_from_rna_path;
};
/**
* #qsort callback for an #FCurve array.
*/
static int fcurve_cmp_for_cache(const void *fcu_a_p, const void *fcu_b_p)
{
const FCurve *fcu_a = *((const FCurve **)fcu_a_p);
const FCurve *fcu_b = *((const FCurve **)fcu_b_p);
const int cmp = strcmp(fcu_a->rna_path, fcu_b->rna_path);
if (cmp != 0) {
return cmp;
}
if (fcu_a->array_index < fcu_b->array_index) {
return -1;
}
if (fcu_a->array_index > fcu_b->array_index) {
return 1;
}
return 0;
}
struct FCurvePathCache *BKE_fcurve_pathcache_create(ListBase *list)
{
const uint fcurve_array_len = BLI_listbase_count(list);
FCurve **fcurve_array = MEM_mallocN(sizeof(*fcurve_array) * fcurve_array_len, __func__);
uint i;
LISTBASE_FOREACH_INDEX (FCurve *, fcu, list, i) {
fcurve_array[i] = fcu;
}
qsort(fcurve_array, fcurve_array_len, sizeof(FCurve *), fcurve_cmp_for_cache);
/* Allow for the case no F-curves share an RNA-path, otherwise this is over-allocated.
* Although in practice it's likely to only be 3-4x as large as is needed
* (with transform channels for e.g.). */
struct FCurvePathCache_Span *span_table = MEM_mallocN(sizeof(*span_table) * fcurve_array_len,
__func__);
/* May over reserve, harmless. */
GHash *span_from_rna_path = BLI_ghash_str_new_ex(__func__, fcurve_array_len);
uint span_index = 0;
i = 0;
while (i < fcurve_array_len) {
uint i_end;
for (i_end = i + 1; i_end < fcurve_array_len; i_end++) {
/* As the indices are sorted, we know a decrease means a new RNA path is found. */
if (fcurve_array[i]->array_index > fcurve_array[i_end]->array_index) {
BLI_assert(!STREQ(fcurve_array[i]->rna_path, fcurve_array[i_end]->rna_path));
break;
}
if (!STREQ(fcurve_array[i]->rna_path, fcurve_array[i_end]->rna_path)) {
break;
}
}
struct FCurvePathCache_Span *span = &span_table[span_index++];
span->index = i;
span->len = i_end - i;
BLI_ghash_insert(span_from_rna_path, fcurve_array[i]->rna_path, span);
i = i_end;
}
struct FCurvePathCache *fcache = MEM_callocN(sizeof(struct FCurvePathCache), __func__);
fcache->fcurve_array = fcurve_array;
fcache->fcurve_array_len = fcurve_array_len;
fcache->span_table = span_table;
fcache->span_from_rna_path = span_from_rna_path;
return fcache;
}
void BKE_fcurve_pathcache_destroy(struct FCurvePathCache *fcache)
{
MEM_freeN(fcache->fcurve_array);
MEM_freeN(fcache->span_table);
BLI_ghash_free(fcache->span_from_rna_path, NULL, NULL);
MEM_freeN(fcache);
}
FCurve *BKE_fcurve_pathcache_find(struct FCurvePathCache *fcache,
const char *rna_path,
const int array_index)
{
const struct FCurvePathCache_Span *span = BLI_ghash_lookup(fcache->span_from_rna_path, rna_path);
if (span == NULL) {
return NULL;
}
FCurve **fcurve = fcache->fcurve_array + span->index;
const uint len = span->len;
for (int i = 0; i < len; i++) {
if (fcurve[i]->array_index == array_index) {
return fcurve[i];
}
/* As these are sorted, early exit. */
if (fcurve[i]->array_index > array_index) {
break;
}
}
return NULL;
}
/**
* Fill in an array of F-Curve, leave NULL when not found.
*
* \return The number of F-Curves found.
*/
int BKE_fcurve_pathcache_find_array(struct FCurvePathCache *fcache,
const char *rna_path,
FCurve **fcurve_result,
int fcurve_result_len)
{
memset(fcurve_result, 0x0, sizeof(*fcurve_result) * fcurve_result_len);
const struct FCurvePathCache_Span *span = BLI_ghash_lookup(fcache->span_from_rna_path, rna_path);
if (span == NULL) {
return 0;
}
int found = 0;
FCurve **fcurve = fcache->fcurve_array + span->index;
const uint len = span->len;
for (int i = 0; i < len; i++) {
/* As these are sorted, early exit. */
if ((uint)fcurve[i]->array_index > (uint)fcurve_result_len) {
break;
}
fcurve_result[fcurve[i]->array_index] = fcurve[i];
found += 1;
}
return found;
}
/** \} */

View File

@ -175,7 +175,7 @@ int MeshComponent::attribute_domain_size(const AttributeDomain domain) const
return mesh_->totvert;
case ATTR_DOMAIN_EDGE:
return mesh_->totedge;
case ATTR_DOMAIN_POLYGON:
case ATTR_DOMAIN_FACE:
return mesh_->totpoly;
default:
break;
@ -259,9 +259,9 @@ static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh,
* only some values are required.
*/
template<typename T>
static void adapt_mesh_domain_corner_to_polygon_impl(const Mesh &mesh,
Span<T> old_values,
MutableSpan<T> r_values)
static void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh,
Span<T> old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totpoly);
attribute_math::DefaultMixer<T> mixer(r_values);
@ -277,8 +277,8 @@ static void adapt_mesh_domain_corner_to_polygon_impl(const Mesh &mesh,
mixer.finalize();
}
static ReadAttributePtr adapt_mesh_domain_corner_to_polygon(const Mesh &mesh,
ReadAttributePtr attribute)
static ReadAttributePtr adapt_mesh_domain_corner_to_face(const Mesh &mesh,
ReadAttributePtr attribute)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
@ -286,7 +286,7 @@ static ReadAttributePtr adapt_mesh_domain_corner_to_polygon(const Mesh &mesh,
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totpoly);
adapt_mesh_domain_corner_to_polygon_impl<T>(mesh, attribute->get_span<T>(), values);
adapt_mesh_domain_corner_to_face_impl<T>(mesh, attribute->get_span<T>(), values);
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
std::move(values));
}
@ -336,9 +336,9 @@ static ReadAttributePtr adapt_mesh_domain_corner_to_edge(const Mesh &mesh,
}
template<typename T>
void adapt_mesh_domain_polygon_to_point_impl(const Mesh &mesh,
Span<T> old_values,
MutableSpan<T> r_values)
void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh,
Span<T> old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totvert);
attribute_math::DefaultMixer<T> mixer(r_values);
@ -356,8 +356,8 @@ void adapt_mesh_domain_polygon_to_point_impl(const Mesh &mesh,
mixer.finalize();
}
static ReadAttributePtr adapt_mesh_domain_polygon_to_point(const Mesh &mesh,
ReadAttributePtr attribute)
static ReadAttributePtr adapt_mesh_domain_face_to_point(const Mesh &mesh,
ReadAttributePtr attribute)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
@ -365,7 +365,7 @@ static ReadAttributePtr adapt_mesh_domain_polygon_to_point(const Mesh &mesh,
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totvert);
adapt_mesh_domain_polygon_to_point_impl<T>(mesh, attribute->get_span<T>(), values);
adapt_mesh_domain_face_to_point_impl<T>(mesh, attribute->get_span<T>(), values);
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
std::move(values));
}
@ -374,9 +374,9 @@ static ReadAttributePtr adapt_mesh_domain_polygon_to_point(const Mesh &mesh,
}
template<typename T>
void adapt_mesh_domain_polygon_to_corner_impl(const Mesh &mesh,
const Span<T> old_values,
MutableSpan<T> r_values)
void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh,
const Span<T> old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totloop);
@ -387,8 +387,8 @@ void adapt_mesh_domain_polygon_to_corner_impl(const Mesh &mesh,
}
}
static ReadAttributePtr adapt_mesh_domain_polygon_to_corner(const Mesh &mesh,
ReadAttributePtr attribute)
static ReadAttributePtr adapt_mesh_domain_face_to_corner(const Mesh &mesh,
ReadAttributePtr attribute)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
@ -396,7 +396,7 @@ static ReadAttributePtr adapt_mesh_domain_polygon_to_corner(const Mesh &mesh,
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totloop);
adapt_mesh_domain_polygon_to_corner_impl<T>(mesh, attribute->get_span<T>(), values);
adapt_mesh_domain_face_to_corner_impl<T>(mesh, attribute->get_span<T>(), values);
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
std::move(values));
}
@ -405,9 +405,9 @@ static ReadAttributePtr adapt_mesh_domain_polygon_to_corner(const Mesh &mesh,
}
template<typename T>
void adapt_mesh_domain_polygon_to_edge_impl(const Mesh &mesh,
const Span<T> old_values,
MutableSpan<T> r_values)
void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh,
const Span<T> old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totedge);
attribute_math::DefaultMixer<T> mixer(r_values);
@ -423,8 +423,8 @@ void adapt_mesh_domain_polygon_to_edge_impl(const Mesh &mesh,
mixer.finalize();
}
static ReadAttributePtr adapt_mesh_domain_polygon_to_edge(const Mesh &mesh,
ReadAttributePtr attribute)
static ReadAttributePtr adapt_mesh_domain_face_to_edge(const Mesh &mesh,
ReadAttributePtr attribute)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
@ -432,7 +432,7 @@ static ReadAttributePtr adapt_mesh_domain_polygon_to_edge(const Mesh &mesh,
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totedge);
adapt_mesh_domain_polygon_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
adapt_mesh_domain_face_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
std::move(values));
}
@ -446,9 +446,9 @@ static ReadAttributePtr adapt_mesh_domain_polygon_to_edge(const Mesh &mesh,
* only some values are required.
*/
template<typename T>
static void adapt_mesh_domain_point_to_polygon_impl(const Mesh &mesh,
const Span<T> old_values,
MutableSpan<T> r_values)
static void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh,
const Span<T> old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totpoly);
attribute_math::DefaultMixer<T> mixer(r_values);
@ -464,8 +464,8 @@ static void adapt_mesh_domain_point_to_polygon_impl(const Mesh &mesh,
mixer.finalize();
}
static ReadAttributePtr adapt_mesh_domain_point_to_polygon(const Mesh &mesh,
ReadAttributePtr attribute)
static ReadAttributePtr adapt_mesh_domain_point_to_face(const Mesh &mesh,
ReadAttributePtr attribute)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
@ -473,7 +473,7 @@ static ReadAttributePtr adapt_mesh_domain_point_to_polygon(const Mesh &mesh,
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totpoly);
adapt_mesh_domain_point_to_polygon_impl<T>(mesh, attribute->get_span<T>(), values);
adapt_mesh_domain_point_to_face_impl<T>(mesh, attribute->get_span<T>(), values);
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
std::move(values));
}
@ -531,7 +531,7 @@ void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh,
for (const int poly_index : IndexRange(mesh.totpoly)) {
const MPoly &poly = mesh.mpoly[poly_index];
/* For every corner, mix the values from the adjacent edges on the polygon. */
/* For every corner, mix the values from the adjacent edges on the face. */
for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
const int loop_index_prev = (loop_index - 1) % poly.totloop;
const MLoop &loop = mesh.mloop[loop_index];
@ -602,9 +602,9 @@ static ReadAttributePtr adapt_mesh_domain_edge_to_point(const Mesh &mesh,
* only some values are required.
*/
template<typename T>
static void adapt_mesh_domain_edge_to_polygon_impl(const Mesh &mesh,
const Span<T> old_values,
MutableSpan<T> r_values)
static void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh,
const Span<T> old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totpoly);
attribute_math::DefaultMixer<T> mixer(r_values);
@ -620,8 +620,8 @@ static void adapt_mesh_domain_edge_to_polygon_impl(const Mesh &mesh,
mixer.finalize();
}
static ReadAttributePtr adapt_mesh_domain_edge_to_polygon(const Mesh &mesh,
ReadAttributePtr attribute)
static ReadAttributePtr adapt_mesh_domain_edge_to_face(const Mesh &mesh,
ReadAttributePtr attribute)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
@ -629,7 +629,7 @@ static ReadAttributePtr adapt_mesh_domain_edge_to_polygon(const Mesh &mesh,
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totpoly);
adapt_mesh_domain_edge_to_polygon_impl<T>(mesh, attribute->get_span<T>(), values);
adapt_mesh_domain_edge_to_face_impl<T>(mesh, attribute->get_span<T>(), values);
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
std::move(values));
}
@ -658,8 +658,8 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr
switch (new_domain) {
case ATTR_DOMAIN_POINT:
return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(attribute));
case ATTR_DOMAIN_POLYGON:
return blender::bke::adapt_mesh_domain_corner_to_polygon(*mesh_, std::move(attribute));
case ATTR_DOMAIN_FACE:
return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, std::move(attribute));
case ATTR_DOMAIN_EDGE:
return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, std::move(attribute));
default:
@ -671,8 +671,8 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr
switch (new_domain) {
case ATTR_DOMAIN_CORNER:
return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(attribute));
case ATTR_DOMAIN_POLYGON:
return blender::bke::adapt_mesh_domain_point_to_polygon(*mesh_, std::move(attribute));
case ATTR_DOMAIN_FACE:
return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, std::move(attribute));
case ATTR_DOMAIN_EDGE:
return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, std::move(attribute));
default:
@ -680,14 +680,14 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr
}
break;
}
case ATTR_DOMAIN_POLYGON: {
case ATTR_DOMAIN_FACE: {
switch (new_domain) {
case ATTR_DOMAIN_POINT:
return blender::bke::adapt_mesh_domain_polygon_to_point(*mesh_, std::move(attribute));
return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, std::move(attribute));
case ATTR_DOMAIN_CORNER:
return blender::bke::adapt_mesh_domain_polygon_to_corner(*mesh_, std::move(attribute));
return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, std::move(attribute));
case ATTR_DOMAIN_EDGE:
return blender::bke::adapt_mesh_domain_polygon_to_edge(*mesh_, std::move(attribute));
return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, std::move(attribute));
default:
break;
}
@ -699,8 +699,8 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr
return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, std::move(attribute));
case ATTR_DOMAIN_POINT:
return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, std::move(attribute));
case ATTR_DOMAIN_POLYGON:
return blender::bke::adapt_mesh_domain_edge_to_polygon(*mesh_, std::move(attribute));
case ATTR_DOMAIN_FACE:
return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, std::move(attribute));
default:
break;
}
@ -774,14 +774,14 @@ static void set_material_index(MPoly &mpoly, const int &index)
static ReadAttributePtr make_material_index_read_attribute(const void *data, const int domain_size)
{
return std::make_unique<DerivedArrayReadAttribute<MPoly, int, get_material_index>>(
ATTR_DOMAIN_POLYGON, Span<MPoly>((const MPoly *)data, domain_size));
ATTR_DOMAIN_FACE, Span<MPoly>((const MPoly *)data, domain_size));
}
static WriteAttributePtr make_material_index_write_attribute(void *data, const int domain_size)
{
return std::make_unique<
DerivedArrayWriteAttribute<MPoly, int, get_material_index, set_material_index>>(
ATTR_DOMAIN_POLYGON, MutableSpan<MPoly>((MPoly *)data, domain_size));
ATTR_DOMAIN_FACE, MutableSpan<MPoly>((MPoly *)data, domain_size));
}
static bool get_shade_smooth(const MPoly &mpoly)
@ -797,14 +797,14 @@ static void set_shade_smooth(MPoly &mpoly, const bool &value)
static ReadAttributePtr make_shade_smooth_read_attribute(const void *data, const int domain_size)
{
return std::make_unique<DerivedArrayReadAttribute<MPoly, bool, get_shade_smooth>>(
ATTR_DOMAIN_POLYGON, Span<MPoly>((const MPoly *)data, domain_size));
ATTR_DOMAIN_FACE, Span<MPoly>((const MPoly *)data, domain_size));
}
static WriteAttributePtr make_shade_smooth_write_attribute(void *data, const int domain_size)
{
return std::make_unique<
DerivedArrayWriteAttribute<MPoly, bool, get_shade_smooth, set_shade_smooth>>(
ATTR_DOMAIN_POLYGON, MutableSpan<MPoly>((MPoly *)data, domain_size));
ATTR_DOMAIN_FACE, MutableSpan<MPoly>((MPoly *)data, domain_size));
}
static float2 get_loop_uv(const MLoopUV &uv)
@ -1045,7 +1045,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
public:
NormalAttributeProvider()
: BuiltinAttributeProvider(
"normal", ATTR_DOMAIN_POLYGON, CD_PROP_FLOAT3, NonCreatable, Readonly, NonDeletable)
"normal", ATTR_DOMAIN_FACE, CD_PROP_FLOAT3, NonCreatable, Readonly, NonDeletable)
{
}
@ -1063,7 +1063,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
const void *data = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
return std::make_unique<ArrayReadAttribute<float3>>(
ATTR_DOMAIN_POLYGON, Span<float3>((const float3 *)data, mesh->totpoly));
ATTR_DOMAIN_FACE, Span<float3>((const float3 *)data, mesh->totpoly));
}
Array<float3> normals(mesh->totpoly);
@ -1072,8 +1072,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
BKE_mesh_calc_poly_normal(poly, &mesh->mloop[poly->loopstart], mesh->mvert, normals[i]);
}
return std::make_unique<OwnedArrayReadAttribute<float3>>(ATTR_DOMAIN_POLYGON,
std::move(normals));
return std::make_unique<OwnedArrayReadAttribute<float3>>(ATTR_DOMAIN_FACE, std::move(normals));
}
WriteAttributePtr try_get_for_write(GeometryComponent &UNUSED(component)) const final
@ -1093,7 +1092,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
bool exists(const GeometryComponent &component) const final
{
return component.attribute_domain_size(ATTR_DOMAIN_POLYGON) != 0;
return component.attribute_domain_size(ATTR_DOMAIN_FACE) != 0;
}
};
@ -1130,9 +1129,9 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
static CustomDataAccessInfo edge_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(edata),
MAKE_CONST_CUSTOM_DATA_GETTER(edata),
update_custom_data_pointers};
static CustomDataAccessInfo polygon_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(pdata),
MAKE_CONST_CUSTOM_DATA_GETTER(pdata),
update_custom_data_pointers};
static CustomDataAccessInfo face_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(pdata),
MAKE_CONST_CUSTOM_DATA_GETTER(pdata),
update_custom_data_pointers};
#undef MAKE_CONST_CUSTOM_DATA_GETTER
#undef MAKE_MUTABLE_CUSTOM_DATA_GETTER
@ -1152,25 +1151,25 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
static NormalAttributeProvider normal;
static BuiltinCustomDataLayerProvider material_index("material_index",
ATTR_DOMAIN_POLYGON,
ATTR_DOMAIN_FACE,
CD_PROP_INT32,
CD_MPOLY,
BuiltinAttributeProvider::NonCreatable,
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::NonDeletable,
polygon_access,
face_access,
make_material_index_read_attribute,
make_material_index_write_attribute,
nullptr);
static BuiltinCustomDataLayerProvider shade_smooth("shade_smooth",
ATTR_DOMAIN_POLYGON,
ATTR_DOMAIN_FACE,
CD_PROP_BOOL,
CD_MPOLY,
BuiltinAttributeProvider::NonCreatable,
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::NonDeletable,
polygon_access,
face_access,
make_shade_smooth_read_attribute,
make_shade_smooth_write_attribute,
nullptr);
@ -1205,7 +1204,7 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access);
static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access);
static CustomDataAttributeProvider edge_custom_data(ATTR_DOMAIN_EDGE, edge_access);
static CustomDataAttributeProvider polygon_custom_data(ATTR_DOMAIN_POLYGON, polygon_access);
static CustomDataAttributeProvider face_custom_data(ATTR_DOMAIN_FACE, face_access);
return ComponentAttributeProviders({&position, &material_index, &shade_smooth, &normal, &crease},
{&uvs,
@ -1214,7 +1213,7 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
&vertex_groups,
&point_custom_data,
&edge_custom_data,
&polygon_custom_data});
&face_custom_data});
}
} // namespace blender::bke

View File

@ -153,16 +153,13 @@ static void geometry_set_collect_recursive(const GeometrySet &geometry_set,
*
* \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances.
*/
Vector<GeometryInstanceGroup> geometry_set_gather_instances(const GeometrySet &geometry_set)
void geometry_set_gather_instances(const GeometrySet &geometry_set,
Vector<GeometryInstanceGroup> &r_instance_groups)
{
Vector<GeometryInstanceGroup> result_vector;
float4x4 unit_transform;
unit_m4(unit_transform.values);
geometry_set_collect_recursive(geometry_set, unit_transform, result_vector);
return result_vector;
geometry_set_collect_recursive(geometry_set, unit_transform, r_instance_groups);
}
void gather_attribute_info(Map<std::string, AttributeKind> &attributes,
@ -436,7 +433,8 @@ GeometrySet geometry_set_realize_mesh_for_modifier(const GeometrySet &geometry_s
}
GeometrySet new_geometry_set = geometry_set;
Vector<GeometryInstanceGroup> set_groups = geometry_set_gather_instances(geometry_set);
Vector<GeometryInstanceGroup> set_groups;
geometry_set_gather_instances(geometry_set, set_groups);
join_instance_groups_mesh(set_groups, true, new_geometry_set);
/* Remove all instances, even though some might contain other non-mesh data. We can't really
* keep only non-mesh instances in general. */
@ -454,7 +452,8 @@ GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set)
GeometrySet new_geometry_set;
Vector<GeometryInstanceGroup> set_groups = geometry_set_gather_instances(geometry_set);
Vector<GeometryInstanceGroup> set_groups;
geometry_set_gather_instances(geometry_set, set_groups);
join_instance_groups_mesh(set_groups, false, new_geometry_set);
join_instance_groups_pointcloud(set_groups, new_geometry_set);
join_instance_groups_volume(set_groups, new_geometry_set);

View File

@ -3663,7 +3663,7 @@ static int generate_perimeter_cap(const float point[4],
/**
* Calculate the perimeter (outline) of a stroke as list of tPerimeterPoint.
* \param subdivisions: Number of subdivions for the start and end caps
* \param subdivisions: Number of subdivisions for the start and end caps
* \return: list of tPerimeterPoint
*/
static ListBase *gpencil_stroke_perimeter_ex(const bGPdata *gpd,
@ -3710,7 +3710,7 @@ static ListBase *gpencil_stroke_perimeter_ex(const bGPdata *gpd,
copy_v3_v3(first_next_pt, &first_next->x);
copy_v3_v3(last_prev_pt, &last_prev->x);
/* edgecase if single point */
/* Edge-case if single point. */
if (gps->totpoints == 1) {
first_next_pt[0] += 1.0f;
last_prev_pt[0] -= 1.0f;
@ -3784,7 +3784,7 @@ static ListBase *gpencil_stroke_perimeter_ex(const bGPdata *gpd,
negate_v2(vec_miter_right);
float angle = dot_v2v2(vec_next, nvec_prev);
/* add two points if angle is close to beeing straight */
/* Add two points if angle is close to being straight. */
if (fabsf(angle) < 0.0001f) {
normalize_v2_length(nvec_prev, radius);
normalize_v2_length(nvec_next, radius);
@ -3910,7 +3910,7 @@ static ListBase *gpencil_stroke_perimeter_ex(const bGPdata *gpd,
/**
* Calculates the perimeter of a stroke projected from the view and
* returns it as a new stroke.
* \param subdivisions: Number of subdivions for the start and end caps
* \param subdivisions: Number of subdivisions for the start and end caps
* \return: bGPDstroke pointer to stroke perimeter
*/
bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d,

View File

@ -437,6 +437,10 @@ static bool lib_override_hierarchy_dependencies_recursive_tag(LibOverrideGroupTa
}
/* We only consider IDs from the same library. */
ID *to_id = *to_id_entry->id_pointer.to;
if (!ID_IS_LINKED(to_id) && !ID_IS_OVERRIDE_LIBRARY(to_id)) {
/* Pure local data is a barrier of dependency in override cases. */
continue;
}
if (to_id != NULL && to_id->lib == id->lib) {
LibOverrideGroupTagData sub_data = *data;
sub_data.id_root = to_id;
@ -812,6 +816,9 @@ bool BKE_lib_override_library_create(
BKE_main_id_clear_newpoins(bmain);
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
/* We need to rebuild some of the deleted override rules (for UI feedback purpose). */
BKE_lib_override_library_main_operations_create(bmain, true);
return success;
}

View File

@ -1364,7 +1364,9 @@ GHashIterator *nodeSocketTypeGetIterator(void)
return BLI_ghashIterator_new(nodesockettypes_hash);
}
struct bNodeSocket *nodeFindSocket(const bNode *node, int in_out, const char *identifier)
struct bNodeSocket *nodeFindSocket(const bNode *node,
eNodeSocketInOut in_out,
const char *identifier)
{
const ListBase *sockets = (in_out == SOCK_IN) ? &node->inputs : &node->outputs;
LISTBASE_FOREACH (bNodeSocket *, sock, sockets) {
@ -1521,7 +1523,7 @@ void nodeModifySocketType(
bNodeSocket *nodeAddSocket(bNodeTree *ntree,
bNode *node,
int in_out,
eNodeSocketInOut in_out,
const char *idname,
const char *identifier,
const char *name)
@ -1543,7 +1545,7 @@ bNodeSocket *nodeAddSocket(bNodeTree *ntree,
bNodeSocket *nodeInsertSocket(bNodeTree *ntree,
bNode *node,
int in_out,
eNodeSocketInOut in_out,
const char *idname,
bNodeSocket *next_sock,
const char *identifier,
@ -1704,7 +1706,7 @@ const char *nodeStaticSocketInterfaceType(int type, int subtype)
bNodeSocket *nodeAddStaticSocket(bNodeTree *ntree,
bNode *node,
int in_out,
eNodeSocketInOut in_out,
int type,
int subtype,
const char *identifier,
@ -1724,7 +1726,7 @@ bNodeSocket *nodeAddStaticSocket(bNodeTree *ntree,
bNodeSocket *nodeInsertStaticSocket(bNodeTree *ntree,
bNode *node,
int in_out,
eNodeSocketInOut in_out,
int type,
int subtype,
bNodeSocket *next_sock,
@ -3220,7 +3222,7 @@ void ntreeLocalMerge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
/* ************ NODE TREE INTERFACE *************** */
static bNodeSocket *make_socket_interface(bNodeTree *ntree,
int in_out,
eNodeSocketInOut in_out,
const char *idname,
const char *name)
{
@ -3256,7 +3258,9 @@ static bNodeSocket *make_socket_interface(bNodeTree *ntree,
return sock;
}
bNodeSocket *ntreeFindSocketInterface(bNodeTree *ntree, int in_out, const char *identifier)
bNodeSocket *ntreeFindSocketInterface(bNodeTree *ntree,
eNodeSocketInOut in_out,
const char *identifier)
{
ListBase *sockets = (in_out == SOCK_IN) ? &ntree->inputs : &ntree->outputs;
LISTBASE_FOREACH (bNodeSocket *, iosock, sockets) {
@ -3268,7 +3272,7 @@ bNodeSocket *ntreeFindSocketInterface(bNodeTree *ntree, int in_out, const char *
}
bNodeSocket *ntreeAddSocketInterface(bNodeTree *ntree,
int in_out,
eNodeSocketInOut in_out,
const char *idname,
const char *name)
{
@ -3284,8 +3288,11 @@ bNodeSocket *ntreeAddSocketInterface(bNodeTree *ntree,
return iosock;
}
bNodeSocket *ntreeInsertSocketInterface(
bNodeTree *ntree, int in_out, const char *idname, bNodeSocket *next_sock, const char *name)
bNodeSocket *ntreeInsertSocketInterface(bNodeTree *ntree,
eNodeSocketInOut in_out,
const char *idname,
bNodeSocket *next_sock,
const char *name)
{
bNodeSocket *iosock = make_socket_interface(ntree, in_out, idname, name);
if (in_out == SOCK_IN) {
@ -3304,7 +3311,7 @@ struct bNodeSocket *ntreeAddSocketInterfaceFromSocket(bNodeTree *ntree,
bNodeSocket *from_sock)
{
bNodeSocket *iosock = ntreeAddSocketInterface(
ntree, from_sock->in_out, from_sock->idname, from_sock->name);
ntree, static_cast<eNodeSocketInOut>(from_sock->in_out), from_sock->idname, from_sock->name);
if (iosock) {
if (iosock->typeinfo->interface_from_socket) {
iosock->typeinfo->interface_from_socket(ntree, iosock, from_node, from_sock);
@ -3319,7 +3326,11 @@ struct bNodeSocket *ntreeInsertSocketInterfaceFromSocket(bNodeTree *ntree,
bNodeSocket *from_sock)
{
bNodeSocket *iosock = ntreeInsertSocketInterface(
ntree, from_sock->in_out, from_sock->idname, next_sock, from_sock->name);
ntree,
static_cast<eNodeSocketInOut>(from_sock->in_out),
from_sock->idname,
next_sock,
from_sock->name);
if (iosock) {
if (iosock->typeinfo->interface_from_socket) {
iosock->typeinfo->interface_from_socket(ntree, iosock, from_node, from_sock);
@ -4903,11 +4914,13 @@ static void registerGeometryNodes()
register_node_type_geo_group();
register_node_type_geo_align_rotation_to_vector();
register_node_type_geo_attribute_clamp();
register_node_type_geo_attribute_color_ramp();
register_node_type_geo_attribute_combine_xyz();
register_node_type_geo_attribute_compare();
register_node_type_geo_attribute_convert();
register_node_type_geo_attribute_fill();
register_node_type_geo_attribute_map_range();
register_node_type_geo_attribute_math();
register_node_type_geo_attribute_mix();
register_node_type_geo_attribute_proximity();
@ -4924,9 +4937,9 @@ static void registerGeometryNodes()
register_node_type_geo_mesh_primitive_cone();
register_node_type_geo_mesh_primitive_cube();
register_node_type_geo_mesh_primitive_cylinder();
register_node_type_geo_mesh_primitive_grid();
register_node_type_geo_mesh_primitive_ico_sphere();
register_node_type_geo_mesh_primitive_line();
register_node_type_geo_mesh_primitive_plane();
register_node_type_geo_mesh_primitive_uv_sphere();
register_node_type_geo_object_info();
register_node_type_geo_point_distribute();

View File

@ -567,9 +567,6 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
/* Set up the codec context */
c = st->codec;
c->thread_count = BLI_system_thread_count();
c->thread_type = FF_THREAD_SLICE;
c->codec_id = codec_id;
c->codec_type = AVMEDIA_TYPE_VIDEO;
@ -727,6 +724,20 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
set_ffmpeg_properties(rd, c, "video", &opts);
if (codec->capabilities & AV_CODEC_CAP_AUTO_THREADS) {
c->thread_count = 0;
}
else {
c->thread_count = BLI_system_thread_count();
}
if (codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) {
c->thread_type = FF_THREAD_FRAME;
}
else if (codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) {
c->thread_type = FF_THREAD_SLICE;
}
if (avcodec_open2(c, codec, &opts) < 0) {
BLI_strncpy(error, IMB_ffmpeg_last_error(), error_size);
av_dict_free(&opts);

View File

@ -206,19 +206,38 @@ template<typename T> struct DefaultHash<T *> {
}
};
template<typename T> uint64_t get_default_hash(const T &v)
{
return DefaultHash<T>{}(v);
}
template<typename T1, typename T2> uint64_t get_default_hash_2(const T1 &v1, const T2 &v2)
{
const uint64_t h1 = get_default_hash(v1);
const uint64_t h2 = get_default_hash(v2);
return h1 ^ (h2 * 19349669);
}
template<typename T1, typename T2, typename T3>
uint64_t get_default_hash_3(const T1 &v1, const T2 &v2, const T3 &v3)
{
const uint64_t h1 = get_default_hash(v1);
const uint64_t h2 = get_default_hash(v2);
const uint64_t h3 = get_default_hash(v3);
return h1 ^ (h2 * 19349669) ^ (h3 * 83492791);
}
template<typename T> struct DefaultHash<std::unique_ptr<T>> {
uint64_t operator()(const std::unique_ptr<T> &value) const
{
return DefaultHash<T *>{}(value.get());
return get_default_hash(value.get());
}
};
template<typename T1, typename T2> struct DefaultHash<std::pair<T1, T2>> {
uint64_t operator()(const std::pair<T1, T2> &value) const
{
uint64_t hash1 = DefaultHash<T1>{}(value.first);
uint64_t hash2 = DefaultHash<T2>{}(value.second);
return hash1 ^ (hash2 * 33);
return get_default_hash_2(value.first, value.second);
}
};

View File

@ -788,6 +788,8 @@ class Set {
template<typename ForwardKey>
const Key &lookup_key_or_add__impl(ForwardKey &&key, const uint64_t hash)
{
this->ensure_can_add();
SET_SLOT_PROBING_BEGIN (hash, slot) {
if (slot.contains(key, is_equal_, hash)) {
return *slot.key();

View File

@ -125,7 +125,7 @@ template<typename T> class UserCounter {
uint64_t hash() const
{
return DefaultHash<T *>{}(data_);
return get_default_hash(data_);
}
friend bool operator==(const UserCounter &a, const UserCounter &b)

View File

@ -263,6 +263,7 @@ set(SRC
BLI_session_uuid.h
BLI_set.hh
BLI_set_slots.hh
BLI_simd.h
BLI_smallhash.h
BLI_sort.h
BLI_sort_utils.h

View File

@ -173,7 +173,7 @@ mpq3 mpq3::cross_poly(Span<mpq3> poly)
uint64_t hash_mpq_class(const mpq_class &value)
{
/* TODO: better/faster implementation of this. */
return DefaultHash<float>{}(static_cast<float>(value.get_d()));
return get_default_hash(static_cast<float>(value.get_d()));
}
uint64_t mpq2::hash() const

View File

@ -97,10 +97,7 @@ class Edge {
uint64_t hash() const
{
constexpr uint64_t h1 = 33;
uint64_t v0hash = DefaultHash<int>{}(v_[0]->id);
uint64_t v1hash = DefaultHash<int>{}(v_[1]->id);
return v0hash ^ (v1hash * h1);
return get_default_hash_2(v_[0]->id, v_[1]->id);
}
};

View File

@ -456,8 +456,8 @@ TEST(set, LookupKeyPtr)
TEST(set, LookupKeyOrAdd)
{
Set<MyKeyType> set;
set.add({1, 10});
set.add({2, 20});
set.lookup_key_or_add({1, 10});
set.lookup_key_or_add({2, 20});
EXPECT_EQ(set.size(), 2);
EXPECT_EQ(set.lookup_key_or_add({2, 40}).attached_data, 20);
EXPECT_EQ(set.size(), 2);

View File

@ -2497,9 +2497,12 @@ static void direct_link_id_common(
/* Link direct data of overrides. */
if (id->override_library) {
BLO_read_data_address(reader, &id->override_library);
BLO_read_list_cb(
reader, &id->override_library->properties, direct_link_id_override_property_cb);
id->override_library->runtime = NULL;
/* Work around file corruption on writing, see T86853. */
if (id->override_library != NULL) {
BLO_read_list_cb(
reader, &id->override_library->properties, direct_link_id_override_property_cb);
id->override_library->runtime = NULL;
}
}
DrawDataList *drawdata = DRW_drawdatalist_from_id(id);

View File

@ -1926,6 +1926,18 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 293, 15)) {
LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
if (ntree->type == NTREE_GEOMETRY) {
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (STREQ(node->idname, "GeometryNodeMeshPlane")) {
STRNCPY(node->idname, "GeometryNodeMeshGrid");
}
}
}
}
}
/**
* Versioning code until next subversion bump goes here.
*

View File

@ -261,17 +261,7 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
FROM_DEFAULT_V4_UCHAR(space_node.nodeclass_shader);
}
/**
* Versioning code until next subversion bump goes here.
*
* \note Be sure to check when bumping the version:
* - #blo_do_versions_userdef in this file.
* - "versioning_{BLENDER_VERSION}.c"
*
* \note Keep this message at the bottom of the function.
*/
{
/* Keep this block, even when empty. */
if (!USER_VERSION_ATLEAST(293, 15)) {
FROM_DEFAULT_V4_UCHAR(space_properties.active);
FROM_DEFAULT_V4_UCHAR(space_info.info_error);
@ -286,6 +276,19 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
btheme->space_spreadsheet = btheme->space_outliner;
}
/**
* Versioning code until next subversion bump goes here.
*
* \note Be sure to check when bumping the version:
* - #blo_do_versions_userdef in this file.
* - "versioning_{BLENDER_VERSION}.c"
*
* \note Keep this message at the bottom of the function.
*/
{
/* Keep this block, even when empty. */
}
#undef FROM_DEFAULT_V4_UCHAR
#undef USER_VERSION_ATLEAST

View File

@ -87,8 +87,6 @@ set(SRC
intern/COM_OpenCLDevice.h
intern/COM_SingleThreadedOperation.cc
intern/COM_SingleThreadedOperation.h
intern/COM_SocketReader.cc
intern/COM_SocketReader.h
intern/COM_WorkPackage.cc
intern/COM_WorkPackage.h
intern/COM_WorkScheduler.cc

View File

@ -20,6 +20,8 @@
#include "COM_defines.h"
#include <cstdio>
#include "BLI_assert.h"
CompositorContext::CompositorContext()
{
this->m_scene = nullptr;
@ -33,9 +35,6 @@ CompositorContext::CompositorContext()
int CompositorContext::getFramenumber() const
{
if (this->m_rd) {
return this->m_rd->cfra;
}
return -1; /* this should never happen */
BLI_assert(m_rd);
return m_rd->cfra;
}

View File

@ -454,7 +454,7 @@ void COM_convert_resolution(NodeOperationBuilder &builder,
NodeOperationOutput *fromSocket,
NodeOperationInput *toSocket)
{
InputResizeMode mode = toSocket->getResizeMode();
ResizeMode mode = toSocket->getResizeMode();
NodeOperation *toOperation = &toSocket->getOperation();
const float toWidth = toOperation->getWidth();
@ -470,22 +470,22 @@ void COM_convert_resolution(NodeOperationBuilder &builder,
float scaleY = 0;
switch (mode) {
case COM_SC_NO_RESIZE:
case ResizeMode::None:
break;
case COM_SC_CENTER:
case ResizeMode::Center:
doCenter = true;
break;
case COM_SC_FIT_WIDTH:
case ResizeMode::FitWidth:
doCenter = true;
doScale = true;
scaleX = scaleY = toWidth / fromWidth;
break;
case COM_SC_FIT_HEIGHT:
case ResizeMode::FitHeight:
doCenter = true;
doScale = true;
scaleX = scaleY = toHeight / fromHeight;
break;
case COM_SC_FIT:
case ResizeMode::FitAny:
doCenter = true;
doScale = true;
scaleX = toWidth / fromWidth;
@ -497,7 +497,7 @@ void COM_convert_resolution(NodeOperationBuilder &builder,
scaleY = scaleX;
}
break;
case COM_SC_STRETCH:
case ResizeMode::Stretch:
doCenter = true;
doScale = true;
scaleX = toWidth / fromWidth;
@ -510,8 +510,8 @@ void COM_convert_resolution(NodeOperationBuilder &builder,
ScaleOperation *scaleOperation = nullptr;
if (doScale) {
scaleOperation = new ScaleOperation();
scaleOperation->getInputSocket(1)->setResizeMode(COM_SC_NO_RESIZE);
scaleOperation->getInputSocket(2)->setResizeMode(COM_SC_NO_RESIZE);
scaleOperation->getInputSocket(1)->setResizeMode(ResizeMode::None);
scaleOperation->getInputSocket(2)->setResizeMode(ResizeMode::None);
first = scaleOperation;
SetValueOperation *sxop = new SetValueOperation();
sxop->setValue(scaleX);
@ -530,8 +530,8 @@ void COM_convert_resolution(NodeOperationBuilder &builder,
}
TranslateOperation *translateOperation = new TranslateOperation();
translateOperation->getInputSocket(1)->setResizeMode(COM_SC_NO_RESIZE);
translateOperation->getInputSocket(2)->setResizeMode(COM_SC_NO_RESIZE);
translateOperation->getInputSocket(1)->setResizeMode(ResizeMode::None);
translateOperation->getInputSocket(2)->setResizeMode(ResizeMode::None);
if (!first) {
first = translateOperation;
}
@ -551,14 +551,14 @@ void COM_convert_resolution(NodeOperationBuilder &builder,
builder.addOperation(translateOperation);
if (doScale) {
translateOperation->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE);
translateOperation->getInputSocket(0)->setResizeMode(ResizeMode::None);
builder.addLink(scaleOperation->getOutputSocket(), translateOperation->getInputSocket(0));
}
/* remove previous link and replace */
builder.removeInputLink(toSocket);
first->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE);
toSocket->setResizeMode(COM_SC_NO_RESIZE);
first->getInputSocket(0)->setResizeMode(ResizeMode::None);
toSocket->setResizeMode(ResizeMode::None);
builder.addLink(fromSocket, first->getInputSocket(0));
builder.addLink(translateOperation->getOutputSocket(), toSocket);
}

View File

@ -70,17 +70,17 @@ class ExecutionGroup;
*
* - Image size conversions: the system can automatically convert when resolutions do not match.
* An NodeInput has a resize mode. This can be any of the following settings.
* - [@ref InputSocketResizeMode.COM_SC_CENTER]:
* - [@ref InputSocketResizeMode.ResizeMode::Center]:
* The center of both images are aligned
* - [@ref InputSocketResizeMode.COM_SC_FIT_WIDTH]:
* - [@ref InputSocketResizeMode.ResizeMode::FitWidth]:
* The width of both images are aligned
* - [@ref InputSocketResizeMode.COM_SC_FIT_HEIGHT]:
* - [@ref InputSocketResizeMode.ResizeMode::FitHeight]:
* The height of both images are aligned
* - [@ref InputSocketResizeMode.COM_SC_FIT]:
* - [@ref InputSocketResizeMode.ResizeMode::FitAny]:
* The width, or the height of both images are aligned to make sure that it fits.
* - [@ref InputSocketResizeMode.COM_SC_STRETCH]:
* - [@ref InputSocketResizeMode.ResizeMode::Stretch]:
* The width and the height of both images are aligned.
* - [@ref InputSocketResizeMode.COM_SC_NO_RESIZE]:
* - [@ref InputSocketResizeMode.ResizeMode::None]:
* Bottom left of the images are aligned.
*
* \see COM_convert_data_type Datatype conversions

View File

@ -22,7 +22,6 @@ class MemoryBuffer;
#include "COM_ExecutionGroup.h"
#include "COM_MemoryProxy.h"
#include "COM_SocketReader.h"
#include "BLI_math.h"
#include "BLI_rect.h"

View File

@ -83,7 +83,7 @@ void NodeGraph::add_node(Node *node,
node->setInstanceKey(key);
node->setIsInActiveGroup(is_active_group);
m_nodes.push_back(node);
m_nodes.append(node);
DebugInfo::node_added(node);
}
@ -156,7 +156,7 @@ void NodeGraph::add_bNode(const CompositorContext &context,
NodeGraph::NodeInputs NodeGraph::find_inputs(const NodeRange &node_range, bNodeSocket *b_socket)
{
NodeInputs result;
for (NodeGraph::NodeIterator it = node_range.first; it != node_range.second; ++it) {
for (blender::Vector<Node *>::iterator it = node_range.first; it != node_range.second; ++it) {
Node *node = *it;
for (int index = 0; index < node->getNumberOfInputSockets(); index++) {
NodeInput *input = node->getInputSocket(index);
@ -170,7 +170,7 @@ NodeGraph::NodeInputs NodeGraph::find_inputs(const NodeRange &node_range, bNodeS
NodeOutput *NodeGraph::find_output(const NodeRange &node_range, bNodeSocket *b_socket)
{
for (NodeGraph::NodeIterator it = node_range.first; it != node_range.second; ++it) {
for (blender::Vector<Node *>::iterator it = node_range.first; it != node_range.second; ++it) {
Node *node = *it;
for (int index = 0; index < node->getNumberOfOutputSockets(); index++) {
NodeOutput *output = node->getOutputSocket(index);

View File

@ -22,7 +22,6 @@
#include <map>
#include <set>
#include <vector>
#include "DNA_node_types.h"
@ -50,18 +49,15 @@ class NodeGraph {
}
};
typedef std::vector<Node *> Nodes;
typedef Nodes::iterator NodeIterator;
private:
Nodes m_nodes;
blender::Vector<Node *> m_nodes;
blender::Vector<Link> m_links;
public:
NodeGraph();
~NodeGraph();
const Nodes &nodes() const
const blender::Vector<Node *> &nodes() const
{
return m_nodes;
}
@ -73,7 +69,8 @@ class NodeGraph {
void from_bNodeTree(const CompositorContext &context, bNodeTree *tree);
protected:
typedef std::pair<NodeIterator, NodeIterator> NodeRange;
typedef std::pair<blender::Vector<Node *>::iterator, blender::Vector<Node *>::iterator>
NodeRange;
typedef std::vector<NodeInput *> NodeInputs;
static bNodeSocket *find_b_node_input(bNode *b_node, const char *identifier);

View File

@ -39,68 +39,47 @@ NodeOperation::NodeOperation()
this->m_btree = nullptr;
}
NodeOperation::~NodeOperation()
NodeOperationOutput *NodeOperation::getOutputSocket(unsigned int index)
{
while (!this->m_outputs.empty()) {
delete (this->m_outputs.back());
this->m_outputs.pop_back();
}
while (!this->m_inputs.empty()) {
delete (this->m_inputs.back());
this->m_inputs.pop_back();
}
return &m_outputs[index];
}
NodeOperationOutput *NodeOperation::getOutputSocket(unsigned int index) const
NodeOperationInput *NodeOperation::getInputSocket(unsigned int index)
{
BLI_assert(index < m_outputs.size());
return m_outputs[index];
return &m_inputs[index];
}
NodeOperationInput *NodeOperation::getInputSocket(unsigned int index) const
void NodeOperation::addInputSocket(DataType datatype, ResizeMode resize_mode)
{
BLI_assert(index < m_inputs.size());
return m_inputs[index];
}
void NodeOperation::addInputSocket(DataType datatype, InputResizeMode resize_mode)
{
NodeOperationInput *socket = new NodeOperationInput(this, datatype, resize_mode);
m_inputs.push_back(socket);
m_inputs.append(NodeOperationInput(this, datatype, resize_mode));
}
void NodeOperation::addOutputSocket(DataType datatype)
{
NodeOperationOutput *socket = new NodeOperationOutput(this, datatype);
m_outputs.push_back(socket);
m_outputs.append(NodeOperationOutput(this, datatype));
}
void NodeOperation::determineResolution(unsigned int resolution[2],
unsigned int preferredResolution[2])
{
unsigned int temp[2];
unsigned int temp2[2];
for (unsigned int index = 0; index < m_inputs.size(); index++) {
NodeOperationInput *input = m_inputs[index];
if (input->isConnected()) {
if (index == this->m_resolutionInputSocketIndex) {
input->determineResolution(resolution, preferredResolution);
temp2[0] = resolution[0];
temp2[1] = resolution[1];
break;
}
}
if (m_resolutionInputSocketIndex < m_inputs.size()) {
NodeOperationInput &input = m_inputs[m_resolutionInputSocketIndex];
input.determineResolution(resolution, preferredResolution);
}
unsigned int temp2[2] = {resolution[0], resolution[1]};
unsigned int temp[2];
for (unsigned int index = 0; index < m_inputs.size(); index++) {
NodeOperationInput *input = m_inputs[index];
if (input->isConnected()) {
if (index != this->m_resolutionInputSocketIndex) {
input->determineResolution(temp, temp2);
}
if (index == this->m_resolutionInputSocketIndex) {
continue;
}
NodeOperationInput &input = m_inputs[index];
if (input.isConnected()) {
input.determineResolution(temp, temp2);
}
}
}
void NodeOperation::setResolutionInputSocketIndex(unsigned int index)
{
this->m_resolutionInputSocketIndex = index;
@ -149,15 +128,6 @@ NodeOperation *NodeOperation::getInputOperation(unsigned int inputSocketIndex)
return nullptr;
}
void NodeOperation::getConnectedInputSockets(Inputs *sockets)
{
for (NodeOperationInput *input : m_inputs) {
if (input->isConnected()) {
sockets->push_back(input);
}
}
}
bool NodeOperation::determineDependingAreaOfInterest(rcti *input,
ReadBufferOperation *readOperation,
rcti *output)
@ -195,9 +165,7 @@ bool NodeOperation::determineDependingAreaOfInterest(rcti *input,
**** OpInput ****
*****************/
NodeOperationInput::NodeOperationInput(NodeOperation *op,
DataType datatype,
InputResizeMode resizeMode)
NodeOperationInput::NodeOperationInput(NodeOperation *op, DataType datatype, ResizeMode resizeMode)
: m_operation(op), m_datatype(datatype), m_resizeMode(resizeMode), m_link(nullptr)
{
}

View File

@ -28,8 +28,8 @@
#include "COM_MemoryBuffer.h"
#include "COM_MemoryProxy.h"
#include "COM_MetaData.h"
#include "COM_Node.h"
#include "COM_SocketReader.h"
#include "clew.h"
@ -37,32 +37,131 @@ class OpenCLDevice;
class ReadBufferOperation;
class WriteBufferOperation;
class NodeOperationInput;
class NodeOperationOutput;
class NodeOperation;
typedef NodeOperation SocketReader;
/**
* \brief Resize modes of inputsockets
* How are the input and working resolutions matched
* \ingroup Model
*/
typedef enum InputResizeMode {
enum class ResizeMode {
/** \brief Center the input image to the center of the working area of the node, no resizing
* occurs */
COM_SC_CENTER = NS_CR_CENTER,
Center = NS_CR_CENTER,
/** \brief The bottom left of the input image is the bottom left of the working area of the node,
* no resizing occurs */
COM_SC_NO_RESIZE = NS_CR_NONE,
None = NS_CR_NONE,
/** \brief Fit the width of the input image to the width of the working area of the node */
COM_SC_FIT_WIDTH = NS_CR_FIT_WIDTH,
FitWidth = NS_CR_FIT_WIDTH,
/** \brief Fit the height of the input image to the height of the working area of the node */
COM_SC_FIT_HEIGHT = NS_CR_FIT_HEIGHT,
FitHeight = NS_CR_FIT_HEIGHT,
/** \brief Fit the width or the height of the input image to the width or height of the working
* area of the node, image will be larger than the working area */
COM_SC_FIT = NS_CR_FIT,
FitAny = NS_CR_FIT,
/** \brief Fit the width and the height of the input image to the width and height of the working
* area of the node, image will be equally larger than the working area */
COM_SC_STRETCH = NS_CR_STRETCH,
} InputResizeMode;
Stretch = NS_CR_STRETCH,
};
enum class PixelSampler {
Nearest = 0,
Bilinear = 1,
Bicubic = 2,
};
class NodeOperationInput {
private:
NodeOperation *m_operation;
/** Datatype of this socket. Is used for automatically data transformation.
* \section data-conversion
*/
DataType m_datatype;
/** Resize mode of this socket */
ResizeMode m_resizeMode;
/** Connected output */
NodeOperationOutput *m_link;
public:
NodeOperationInput(NodeOperation *op,
DataType datatype,
ResizeMode resizeMode = ResizeMode::Center);
NodeOperation &getOperation() const
{
return *m_operation;
}
DataType getDataType() const
{
return m_datatype;
}
void setLink(NodeOperationOutput *link)
{
m_link = link;
}
NodeOperationOutput *getLink() const
{
return m_link;
}
bool isConnected() const
{
return m_link;
}
void setResizeMode(ResizeMode resizeMode)
{
this->m_resizeMode = resizeMode;
}
ResizeMode getResizeMode() const
{
return this->m_resizeMode;
}
SocketReader *getReader();
void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]);
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:NodeOperation")
#endif
};
class NodeOperationOutput {
private:
NodeOperation *m_operation;
/** Datatype of this socket. Is used for automatically data transformation.
* \section data-conversion
*/
DataType m_datatype;
public:
NodeOperationOutput(NodeOperation *op, DataType datatype);
NodeOperation &getOperation() const
{
return *m_operation;
}
DataType getDataType() const
{
return m_datatype;
}
/**
* \brief determine the resolution of this data going through this socket
* \param resolution: the result of this operation
* \param preferredResolution: the preferable resolution as no resolution could be determined
*/
void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]);
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:NodeOperation")
#endif
};
/**
* \brief NodeOperation contains calculation logic
@ -70,14 +169,10 @@ typedef enum InputResizeMode {
* Subclasses needs to implement the execution method (defined in SocketReader) to implement logic.
* \ingroup Model
*/
class NodeOperation : public SocketReader {
public:
typedef std::vector<NodeOperationInput *> Inputs;
typedef std::vector<NodeOperationOutput *> Outputs;
class NodeOperation {
private:
Inputs m_inputs;
Outputs m_outputs;
blender::Vector<NodeOperationInput> m_inputs;
blender::Vector<NodeOperationOutput> m_outputs;
/**
* \brief the index of the input socket that will be used to determine the resolution
@ -119,8 +214,21 @@ class NodeOperation : public SocketReader {
*/
bool m_isResolutionSet;
protected:
/**
* Width of the output of this operation.
*/
unsigned int m_width;
/**
* Height of the output of this operation.
*/
unsigned int m_height;
public:
virtual ~NodeOperation();
virtual ~NodeOperation()
{
}
unsigned int getNumberOfInputSockets() const
{
@ -130,19 +238,15 @@ class NodeOperation : public SocketReader {
{
return m_outputs.size();
}
NodeOperationOutput *getOutputSocket(unsigned int index) const;
NodeOperationOutput *getOutputSocket() const
{
return getOutputSocket(0);
}
NodeOperationInput *getInputSocket(unsigned int index) const;
NodeOperationOutput *getOutputSocket(unsigned int index = 0);
NodeOperationInput *getInputSocket(unsigned int index);
/** Check if this is an input operation
* An input operation is an operation that only has output sockets and no input sockets
*/
bool isInputOperation() const
{
return m_inputs.empty();
return m_inputs.is_empty();
}
/**
@ -259,8 +363,6 @@ class NodeOperation : public SocketReader {
}
}
void getConnectedInputSockets(Inputs *sockets);
/**
* \brief is this operation complex
*
@ -373,10 +475,58 @@ class NodeOperation : public SocketReader {
}
}
unsigned int getWidth() const
{
return m_width;
}
unsigned int getHeight() const
{
return m_height;
}
inline void readSampled(float result[4], float x, float y, PixelSampler sampler)
{
executePixelSampled(result, x, y, sampler);
}
inline void readFiltered(float result[4], float x, float y, float dx[2], float dy[2])
{
executePixelFiltered(result, x, y, dx, dy);
}
inline void read(float result[4], int x, int y, void *chunkData)
{
executePixel(result, x, y, chunkData);
}
virtual void *initializeTileData(rcti * /*rect*/)
{
return 0;
}
virtual void deinitializeTileData(rcti * /*rect*/, void * /*data*/)
{
}
virtual MemoryBuffer *getInputMemoryBuffer(MemoryBuffer ** /*memoryBuffers*/)
{
return 0;
}
/**
* Return the meta data associated with this branch.
*
* The return parameter holds an instance or is an nullptr. */
virtual std::unique_ptr<MetaData> getMetaData()
{
return std::unique_ptr<MetaData>();
}
protected:
NodeOperation();
void addInputSocket(DataType datatype, InputResizeMode resize_mode = COM_SC_CENTER);
void addInputSocket(DataType datatype, ResizeMode resize_mode = ResizeMode::Center);
void addOutputSocket(DataType datatype);
void setWidth(unsigned int width)
@ -416,6 +566,50 @@ class NodeOperation : public SocketReader {
this->m_openCL = openCL;
}
/**
* \brief calculate a single pixel
* \note this method is called for non-complex
* \param result: is a float[4] array to store the result
* \param x: the x-coordinate of the pixel to calculate in image space
* \param y: the y-coordinate of the pixel to calculate in image space
* \param inputBuffers: chunks that can be read by their ReadBufferOperation.
*/
virtual void executePixelSampled(float /*output*/[4],
float /*x*/,
float /*y*/,
PixelSampler /*sampler*/)
{
}
/**
* \brief calculate a single pixel
* \note this method is called for complex
* \param result: is a float[4] array to store the result
* \param x: the x-coordinate of the pixel to calculate in image space
* \param y: the y-coordinate of the pixel to calculate in image space
* \param inputBuffers: chunks that can be read by their ReadBufferOperation.
* \param chunkData: chunk specific data a during execution time.
*/
virtual void executePixel(float output[4], int x, int y, void * /*chunkData*/)
{
executePixelSampled(output, x, y, PixelSampler::Nearest);
}
/**
* \brief calculate a single pixel using an EWA filter
* \note this method is called for complex
* \param result: is a float[4] array to store the result
* \param x: the x-coordinate of the pixel to calculate in image space
* \param y: the y-coordinate of the pixel to calculate in image space
* \param dx:
* \param dy:
* \param inputBuffers: chunks that can be read by their ReadBufferOperation.
*/
virtual void executePixelFiltered(
float /*output*/[4], float /*x*/, float /*y*/, float /*dx*/[2], float /*dy*/[2])
{
}
/* allow the DebugInfo class to look at internals */
friend class DebugInfo;
@ -423,96 +617,3 @@ class NodeOperation : public SocketReader {
MEM_CXX_CLASS_ALLOC_FUNCS("COM:NodeOperation")
#endif
};
class NodeOperationInput {
private:
NodeOperation *m_operation;
/** Datatype of this socket. Is used for automatically data transformation.
* \section data-conversion
*/
DataType m_datatype;
/** Resize mode of this socket */
InputResizeMode m_resizeMode;
/** Connected output */
NodeOperationOutput *m_link;
public:
NodeOperationInput(NodeOperation *op,
DataType datatype,
InputResizeMode resizeMode = COM_SC_CENTER);
NodeOperation &getOperation() const
{
return *m_operation;
}
DataType getDataType() const
{
return m_datatype;
}
void setLink(NodeOperationOutput *link)
{
m_link = link;
}
NodeOperationOutput *getLink() const
{
return m_link;
}
bool isConnected() const
{
return m_link;
}
void setResizeMode(InputResizeMode resizeMode)
{
this->m_resizeMode = resizeMode;
}
InputResizeMode getResizeMode() const
{
return this->m_resizeMode;
}
SocketReader *getReader();
void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]);
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:NodeOperation")
#endif
};
class NodeOperationOutput {
private:
NodeOperation *m_operation;
/** Datatype of this socket. Is used for automatically data transformation.
* \section data-conversion
*/
DataType m_datatype;
public:
NodeOperationOutput(NodeOperation *op, DataType datatype);
NodeOperation &getOperation() const
{
return *m_operation;
}
DataType getDataType() const
{
return m_datatype;
}
/**
* \brief determine the resolution of this data going through this socket
* \param resolution: the result of this operation
* \param preferredResolution: the preferable resolution as no resolution could be determined
*/
void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]);
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:NodeOperation")
#endif
};

View File

@ -53,9 +53,7 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system)
/* interface handle for nodes */
NodeConverter converter(this);
for (int index = 0; index < m_graph.nodes().size(); index++) {
Node *node = (Node *)m_graph.nodes()[index];
for (Node *node : m_graph.nodes()) {
m_current_node = node;
DebugInfo::node_to_operations(node);
@ -401,7 +399,7 @@ void NodeOperationBuilder::determineResolutions()
{
blender::Vector<Link> convert_links;
for (const Link &link : m_links) {
if (link.to()->getResizeMode() != COM_SC_NO_RESIZE) {
if (link.to()->getResizeMode() != ResizeMode::None) {
NodeOperation &from_op = link.from()->getOperation();
NodeOperation &to_op = link.to()->getOperation();
if (from_op.getWidth() != to_op.getWidth() || from_op.getHeight() != to_op.getHeight()) {

View File

@ -1,19 +0,0 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright 2011, Blender Foundation.
*/
#include "COM_SocketReader.h"

View File

@ -1,153 +0,0 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright 2011, Blender Foundation.
*/
#pragma once
#include "BLI_rect.h"
#include "COM_MetaData.h"
#include "COM_defines.h"
#include <memory>
#include <optional>
#ifdef WITH_CXX_GUARDEDALLOC
# include "MEM_guardedalloc.h"
#endif
typedef enum PixelSampler {
COM_PS_NEAREST = 0,
COM_PS_BILINEAR = 1,
COM_PS_BICUBIC = 2,
} PixelSampler;
class MemoryBuffer;
/**
* \brief Helper class for reading socket data.
* Only use this class for dispatching (un-ary and n-ary) executions.
* \ingroup Execution
*/
class SocketReader {
private:
protected:
/**
* \brief Holds the width of the output of this operation.
*/
unsigned int m_width;
/**
* \brief Holds the height of the output of this operation.
*/
unsigned int m_height;
/**
* \brief calculate a single pixel
* \note this method is called for non-complex
* \param result: is a float[4] array to store the result
* \param x: the x-coordinate of the pixel to calculate in image space
* \param y: the y-coordinate of the pixel to calculate in image space
* \param inputBuffers: chunks that can be read by their ReadBufferOperation.
*/
virtual void executePixelSampled(float /*output*/[4],
float /*x*/,
float /*y*/,
PixelSampler /*sampler*/)
{
}
/**
* \brief calculate a single pixel
* \note this method is called for complex
* \param result: is a float[4] array to store the result
* \param x: the x-coordinate of the pixel to calculate in image space
* \param y: the y-coordinate of the pixel to calculate in image space
* \param inputBuffers: chunks that can be read by their ReadBufferOperation.
* \param chunkData: chunk specific data a during execution time.
*/
virtual void executePixel(float output[4], int x, int y, void * /*chunkData*/)
{
executePixelSampled(output, x, y, COM_PS_NEAREST);
}
/**
* \brief calculate a single pixel using an EWA filter
* \note this method is called for complex
* \param result: is a float[4] array to store the result
* \param x: the x-coordinate of the pixel to calculate in image space
* \param y: the y-coordinate of the pixel to calculate in image space
* \param dx:
* \param dy:
* \param inputBuffers: chunks that can be read by their ReadBufferOperation.
*/
virtual void executePixelFiltered(
float /*output*/[4], float /*x*/, float /*y*/, float /*dx*/[2], float /*dy*/[2])
{
}
public:
inline void readSampled(float result[4], float x, float y, PixelSampler sampler)
{
executePixelSampled(result, x, y, sampler);
}
inline void read(float result[4], int x, int y, void *chunkData)
{
executePixel(result, x, y, chunkData);
}
inline void readFiltered(float result[4], float x, float y, float dx[2], float dy[2])
{
executePixelFiltered(result, x, y, dx, dy);
}
virtual void *initializeTileData(rcti * /*rect*/)
{
return 0;
}
virtual void deinitializeTileData(rcti * /*rect*/, void * /*data*/)
{
}
virtual ~SocketReader()
{
}
virtual MemoryBuffer *getInputMemoryBuffer(MemoryBuffer ** /*memoryBuffers*/)
{
return 0;
}
inline unsigned int getWidth() const
{
return this->m_width;
}
inline unsigned int getHeight() const
{
return this->m_height;
}
/* Return the meta data associated with this branch.
*
* The return parameter holds an instance or is an nullptr. */
virtual std::unique_ptr<MetaData> getMetaData() const
{
return std::unique_ptr<MetaData>();
}
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:SocketReader")
#endif
};

View File

@ -60,7 +60,7 @@ void BoxMaskNode::convertToOperations(NodeConverter &converter,
scaleOperation->setOffset(0.0f, 0.0f);
scaleOperation->setNewWidth(rd->xsch * render_size_factor);
scaleOperation->setNewHeight(rd->ysch * render_size_factor);
scaleOperation->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE);
scaleOperation->getInputSocket(0)->setResizeMode(ResizeMode::None);
converter.addOperation(scaleOperation);
converter.addLink(valueOperation->getOutputSocket(0), scaleOperation->getInputSocket(0));

View File

@ -60,7 +60,7 @@ void EllipseMaskNode::convertToOperations(NodeConverter &converter,
scaleOperation->setOffset(0.0f, 0.0f);
scaleOperation->setNewWidth(rd->xsch * render_size_factor);
scaleOperation->setNewHeight(rd->ysch * render_size_factor);
scaleOperation->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE);
scaleOperation->getInputSocket(0)->setResizeMode(ResizeMode::None);
converter.addOperation(scaleOperation);
converter.addLink(valueOperation->getOutputSocket(0), scaleOperation->getInputSocket(0));

View File

@ -65,7 +65,7 @@ void GlareNode::convertToOperations(NodeConverter &converter,
MixGlareOperation *mixoperation = new MixGlareOperation();
mixoperation->setResolutionInputSocketIndex(1);
mixoperation->getInputSocket(2)->setResizeMode(COM_SC_FIT);
mixoperation->getInputSocket(2)->setResizeMode(ResizeMode::FitAny);
converter.addOperation(glareoperation);
converter.addOperation(thresholdOperation);

View File

@ -79,7 +79,7 @@ void ScaleNode::convertToOperations(NodeConverter &converter,
operation->setOffset(bnode->custom3, bnode->custom4);
operation->setNewWidth(rd->xsch * render_size_factor);
operation->setNewHeight(rd->ysch * render_size_factor);
operation->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE);
operation->getInputSocket(0)->setResizeMode(ResizeMode::None);
converter.addOperation(operation);
converter.mapInputSocket(inputSocket, operation->getInputSocket(0));

View File

@ -167,7 +167,7 @@ void BlurBaseOperation::updateSize()
{
if (!this->m_sizeavailable) {
float result[4];
this->getInputSocketReader(1)->readSampled(result, 0, 0, COM_PS_NEAREST);
this->getInputSocketReader(1)->readSampled(result, 0, 0, PixelSampler::Nearest);
this->m_size = result[0];
this->m_sizeavailable = true;
}

View File

@ -25,7 +25,7 @@
BokehBlurOperation::BokehBlurOperation()
{
this->addInputSocket(DataType::Color);
this->addInputSocket(DataType::Color, COM_SC_NO_RESIZE);
this->addInputSocket(DataType::Color, ResizeMode::None);
this->addInputSocket(DataType::Value);
this->addInputSocket(DataType::Value);
this->addOutputSocket(DataType::Color);
@ -76,7 +76,7 @@ void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data)
float tempBoundingBox[4];
float bokeh[4];
this->m_inputBoundingBoxReader->readSampled(tempBoundingBox, x, y, COM_PS_NEAREST);
this->m_inputBoundingBoxReader->readSampled(tempBoundingBox, x, y, PixelSampler::Nearest);
if (tempBoundingBox[0] > 0.0f) {
float multiplier_accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
@ -90,7 +90,7 @@ void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data)
zero_v4(color_accum);
if (pixelSize < 2) {
this->m_inputProgram->readSampled(color_accum, x, y, COM_PS_NEAREST);
this->m_inputProgram->readSampled(color_accum, x, y, PixelSampler::Nearest);
multiplier_accum[0] = 1.0f;
multiplier_accum[1] = 1.0f;
multiplier_accum[2] = 1.0f;
@ -115,7 +115,7 @@ void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data)
for (int nx = minx; nx < maxx; nx += step) {
float u = this->m_bokehMidX - (nx - x) * m;
float v = this->m_bokehMidY - (ny - y) * m;
this->m_inputBokehProgram->readSampled(bokeh, u, v, COM_PS_NEAREST);
this->m_inputBokehProgram->readSampled(bokeh, u, v, PixelSampler::Nearest);
madd_v4_v4v4(color_accum, bokeh, &buffer[bufferindex]);
add_v4_v4(multiplier_accum, bokeh);
bufferindex += offsetadd;
@ -127,7 +127,7 @@ void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data)
output[3] = color_accum[3] * (1.0f / multiplier_accum[3]);
}
else {
this->m_inputProgram->readSampled(output, x, y, COM_PS_NEAREST);
this->m_inputProgram->readSampled(output, x, y, PixelSampler::Nearest);
}
}
@ -224,7 +224,7 @@ void BokehBlurOperation::updateSize()
{
if (!this->m_sizeavailable) {
float result[4];
this->getInputSocketReader(3)->readSampled(result, 0, 0, COM_PS_NEAREST);
this->getInputSocketReader(3)->readSampled(result, 0, 0, PixelSampler::Nearest);
this->m_size = result[0];
CLAMP(this->m_size, 0.0f, 10.0f);
this->m_sizeavailable = true;

View File

@ -24,7 +24,7 @@
CalculateMeanOperation::CalculateMeanOperation()
{
this->addInputSocket(DataType::Color, COM_SC_NO_RESIZE);
this->addInputSocket(DataType::Color, ResizeMode::None);
this->addOutputSocket(DataType::Value);
this->m_imageReader = nullptr;
this->m_iscalculated = false;

View File

@ -196,14 +196,14 @@ void CompositorOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
for (x = x1; x < x2 && (!breaked); x++) {
int input_x = x + dx, input_y = y + dy;
this->m_imageInput->readSampled(color, input_x, input_y, COM_PS_NEAREST);
this->m_imageInput->readSampled(color, input_x, input_y, PixelSampler::Nearest);
if (this->m_useAlphaInput) {
this->m_alphaInput->readSampled(&(color[3]), input_x, input_y, COM_PS_NEAREST);
this->m_alphaInput->readSampled(&(color[3]), input_x, input_y, PixelSampler::Nearest);
}
copy_v4_v4(buffer + offset4, color);
this->m_depthInput->readSampled(color, input_x, input_y, COM_PS_NEAREST);
this->m_depthInput->readSampled(color, input_x, input_y, PixelSampler::Nearest);
zbuffer[offset] = color[0];
offset4 += COM_NUM_CHANNELS_COLOR;
offset++;

View File

@ -21,7 +21,7 @@
CropBaseOperation::CropBaseOperation()
{
this->addInputSocket(DataType::Color, COM_SC_NO_RESIZE);
this->addInputSocket(DataType::Color, ResizeMode::None);
this->addOutputSocket(DataType::Color);
this->m_inputOperation = nullptr;
this->m_settings = nullptr;

View File

@ -66,7 +66,7 @@ void DirectionalBlurOperation::executePixel(float output[4], int x, int y, void
const int iterations = pow(2.0f, this->m_data->iter);
float col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float col2[4] = {0.0f, 0.0f, 0.0f, 0.0f};
this->m_inputProgram->readSampled(col2, x, y, COM_PS_BILINEAR);
this->m_inputProgram->readSampled(col2, x, y, PixelSampler::Bilinear);
float ltx = this->m_tx;
float lty = this->m_ty;
float lsc = this->m_sc;
@ -82,7 +82,7 @@ void DirectionalBlurOperation::executePixel(float output[4], int x, int y, void
this->m_inputProgram->readSampled(col,
cs * u + ss * v + this->m_center_x_pix,
cs * v - ss * u + this->m_center_y_pix,
COM_PS_BILINEAR);
PixelSampler::Bilinear);
add_v4_v4(col2, col);

View File

@ -56,7 +56,7 @@ void DisplaceOperation::executePixelSampled(float output[4],
pixelTransform(xy, uv, deriv);
if (is_zero_v2(deriv[0]) && is_zero_v2(deriv[1])) {
this->m_inputColorProgram->readSampled(output, uv[0], uv[1], COM_PS_BILINEAR);
this->m_inputColorProgram->readSampled(output, uv[0], uv[1], PixelSampler::Bilinear);
}
else {
/* EWA filtering (without nearest it gets blurry with NO distortion) */
@ -76,7 +76,7 @@ bool DisplaceOperation::read_displacement(
}
float col[4];
m_inputVectorProgram->readSampled(col, x, y, COM_PS_BILINEAR);
m_inputVectorProgram->readSampled(col, x, y, PixelSampler::Bilinear);
r_u = origin[0] - col[0] * xscale;
r_v = origin[1] - col[1] * yscale;
return true;
@ -88,9 +88,9 @@ void DisplaceOperation::pixelTransform(const float xy[2], float r_uv[2], float r
float uv[2]; /* temporary variables for derivative estimation */
int num;
m_inputScaleXProgram->readSampled(col, xy[0], xy[1], COM_PS_NEAREST);
m_inputScaleXProgram->readSampled(col, xy[0], xy[1], PixelSampler::Nearest);
float xs = col[0];
m_inputScaleYProgram->readSampled(col, xy[0], xy[1], COM_PS_NEAREST);
m_inputScaleYProgram->readSampled(col, xy[0], xy[1], PixelSampler::Nearest);
float ys = col[0];
/* clamp x and y displacement to triple image resolution -
* to prevent hangs from huge values mistakenly plugged in eg. z buffers */

View File

@ -23,7 +23,7 @@
GlareThresholdOperation::GlareThresholdOperation()
{
this->addInputSocket(DataType::Color, COM_SC_FIT);
this->addInputSocket(DataType::Color, ResizeMode::FitAny);
this->addOutputSocket(DataType::Color);
this->m_inputProgram = nullptr;
}

View File

@ -123,13 +123,13 @@ static void sampleImageAtLocation(
{
if (ibuf->rect_float) {
switch (sampler) {
case COM_PS_NEAREST:
case PixelSampler::Nearest:
nearest_interpolation_color(ibuf, nullptr, color, x, y);
break;
case COM_PS_BILINEAR:
case PixelSampler::Bilinear:
bilinear_interpolation_color(ibuf, nullptr, color, x, y);
break;
case COM_PS_BICUBIC:
case PixelSampler::Bicubic:
bicubic_interpolation_color(ibuf, nullptr, color, x, y);
break;
}
@ -137,13 +137,13 @@ static void sampleImageAtLocation(
else {
unsigned char byte_color[4];
switch (sampler) {
case COM_PS_NEAREST:
case PixelSampler::Nearest:
nearest_interpolation_color(ibuf, byte_color, nullptr, x, y);
break;
case COM_PS_BILINEAR:
case PixelSampler::Bilinear:
bilinear_interpolation_color(ibuf, byte_color, nullptr, x, y);
break;
case COM_PS_BICUBIC:
case PixelSampler::Bicubic:
bicubic_interpolation_color(ibuf, byte_color, nullptr, x, y);
break;
}

View File

@ -21,7 +21,7 @@
MapUVOperation::MapUVOperation()
{
this->addInputSocket(DataType::Color, COM_SC_NO_RESIZE);
this->addInputSocket(DataType::Color, ResizeMode::None);
this->addInputSocket(DataType::Vector);
this->addOutputSocket(DataType::Color);
this->m_alpha = 0.0f;
@ -89,7 +89,7 @@ bool MapUVOperation::read_uv(float x, float y, float &r_u, float &r_v, float &r_
}
float vector[3];
m_inputUVProgram->readSampled(vector, x, y, COM_PS_BILINEAR);
m_inputUVProgram->readSampled(vector, x, y, PixelSampler::Bilinear);
r_u = vector[0] * m_inputColorProgram->getWidth();
r_v = vector[1] * m_inputColorProgram->getHeight();
r_alpha = vector[2];

View File

@ -101,13 +101,13 @@ void MovieClipBaseOperation::executePixelSampled(float output[4],
}
else {
switch (sampler) {
case COM_PS_NEAREST:
case PixelSampler::Nearest:
nearest_interpolation_color(ibuf, nullptr, output, x, y);
break;
case COM_PS_BILINEAR:
case PixelSampler::Bilinear:
bilinear_interpolation_color(ibuf, nullptr, output, x, y);
break;
case COM_PS_BICUBIC:
case PixelSampler::Bicubic:
bicubic_interpolation_color(ibuf, nullptr, output, x, y);
break;
}

View File

@ -107,10 +107,10 @@ void MovieDistortionOperation::executePixelSampled(float output[4],
float u = out[0] * aspx /* + 0.5 * overscan * w */,
v = (out[1] * aspy /* + 0.5 * overscan * h */) * pixel_aspect;
this->m_inputOperation->readSampled(output, u, v, COM_PS_BILINEAR);
this->m_inputOperation->readSampled(output, u, v, PixelSampler::Bilinear);
}
else {
this->m_inputOperation->readSampled(output, x, y, COM_PS_BILINEAR);
this->m_inputOperation->readSampled(output, x, y, PixelSampler::Bilinear);
}
}

View File

@ -49,7 +49,7 @@ ImBuf *MultilayerBaseOperation::getImBuf()
return nullptr;
}
std::unique_ptr<MetaData> MultilayerColorOperation::getMetaData() const
std::unique_ptr<MetaData> MultilayerColorOperation::getMetaData()
{
BLI_assert(this->m_buffer);
MetaDataExtractCallbackData callback_data = {nullptr};
@ -86,13 +86,13 @@ void MultilayerColorOperation::executePixelSampled(float output[4],
else {
if (this->m_numberOfChannels == 4) {
switch (sampler) {
case COM_PS_NEAREST:
case PixelSampler::Nearest:
nearest_interpolation_color(this->m_buffer, nullptr, output, x, y);
break;
case COM_PS_BILINEAR:
case PixelSampler::Bilinear:
bilinear_interpolation_color(this->m_buffer, nullptr, output, x, y);
break;
case COM_PS_BICUBIC:
case PixelSampler::Bicubic:
bicubic_interpolation_color(this->m_buffer, nullptr, output, x, y);
break;
}

View File

@ -45,7 +45,7 @@ class MultilayerColorOperation : public MultilayerBaseOperation {
this->addOutputSocket(DataType::Color);
}
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
std::unique_ptr<MetaData> getMetaData() const override;
std::unique_ptr<MetaData> getMetaData() override;
};
class MultilayerValueOperation : public MultilayerBaseOperation {

View File

@ -191,7 +191,7 @@ static void write_buffer_rect(rcti *rect,
for (y = y1; y < y2 && (!breaked); y++) {
for (x = x1; x < x2 && (!breaked); x++) {
reader->readSampled(color, x, y, COM_PS_NEAREST);
reader->readSampled(color, x, y, PixelSampler::Nearest);
for (i = 0; i < size; i++) {
buffer[offset + i] = color[i];

View File

@ -60,7 +60,7 @@ static void readCornersFromSockets(rcti *rect, SocketReader *readers[4], float c
{
for (int i = 0; i < 4; i++) {
float result[4] = {0.0f, 0.0f, 0.0f, 0.0f};
readers[i]->readSampled(result, rect->xmin, rect->ymin, COM_PS_NEAREST);
readers[i]->readSampled(result, rect->xmin, rect->ymin, PixelSampler::Nearest);
corners[i][0] = result[0];
corners[i][1] = result[1];
}

View File

@ -46,7 +46,7 @@ BLI_INLINE void warpCoord(float x, float y, float matrix[3][3], float uv[2], flo
PlaneDistortWarpImageOperation::PlaneDistortWarpImageOperation()
{
this->addInputSocket(DataType::Color, COM_SC_NO_RESIZE);
this->addInputSocket(DataType::Color, ResizeMode::None);
this->addOutputSocket(DataType::Color);
this->m_pixelReader = nullptr;
this->m_motion_blur_samples = 1;

View File

@ -39,7 +39,7 @@ PreviewOperation::PreviewOperation(const ColorManagedViewSettings *viewSettings,
const unsigned int defaultHeight)
{
this->addInputSocket(DataType::Color, COM_SC_NO_RESIZE);
this->addInputSocket(DataType::Color, ResizeMode::None);
this->m_preview = nullptr;
this->m_outputBuffer = nullptr;
this->m_input = nullptr;
@ -104,7 +104,7 @@ void PreviewOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
color[1] = 0.0f;
color[2] = 0.0f;
color[3] = 1.0f;
this->m_input->readSampled(color, rx, ry, COM_PS_NEAREST);
this->m_input->readSampled(color, rx, ry, PixelSampler::Nearest);
IMB_colormanagement_processor_apply_v4(cm_processor, color);
rgba_float_to_uchar(this->m_outputBuffer + offset, color);
offset += 4;

View File

@ -103,7 +103,7 @@ void ProjectorLensDistortionOperation::updateDispersion()
this->lockMutex();
if (!this->m_dispersionAvailable) {
float result[4];
this->getInputSocketReader(1)->readSampled(result, 1, 1, COM_PS_NEAREST);
this->getInputSocketReader(1)->readSampled(result, 1, 1, PixelSampler::Nearest);
this->m_dispersion = result[0];
this->m_kr = 0.25f * max_ff(min_ff(this->m_dispersion, 1.0f), 0.0f);
this->m_kr2 = this->m_kr * 20;

View File

@ -60,14 +60,14 @@ void ReadBufferOperation::executePixelSampled(float output[4],
}
else {
switch (sampler) {
case COM_PS_NEAREST:
case PixelSampler::Nearest:
m_buffer->read(output, x, y);
break;
case COM_PS_BILINEAR:
case PixelSampler::Bilinear:
default:
m_buffer->readBilinear(output, x, y);
break;
case COM_PS_BICUBIC:
case PixelSampler::Bicubic:
m_buffer->readBilinear(output, x, y);
break;
}
@ -85,7 +85,7 @@ void ReadBufferOperation::executePixelExtend(float output[4],
/* write buffer has a single value stored at (0,0) */
m_buffer->read(output, 0, 0);
}
else if (sampler == COM_PS_NEAREST) {
else if (sampler == PixelSampler::Nearest) {
m_buffer->read(output, x, y, extend_x, extend_y);
}
else {

View File

@ -92,7 +92,7 @@ void RenderLayersProg::doInterpolation(float output[4], float x, float y, PixelS
}
switch (sampler) {
case COM_PS_NEAREST: {
case PixelSampler::Nearest: {
offset = (iy * width + ix) * this->m_elementsize;
if (this->m_elementsize == 1) {
@ -107,12 +107,12 @@ void RenderLayersProg::doInterpolation(float output[4], float x, float y, PixelS
break;
}
case COM_PS_BILINEAR:
case PixelSampler::Bilinear:
BLI_bilinear_interpolation_fl(
this->m_inputBuffer, output, width, height, this->m_elementsize, x, y);
break;
case COM_PS_BICUBIC:
case PixelSampler::Bicubic:
BLI_bicubic_interpolation_fl(
this->m_inputBuffer, output, width, height, this->m_elementsize, x, y);
break;
@ -216,7 +216,7 @@ void RenderLayersProg::determineResolution(unsigned int resolution[2],
}
}
std::unique_ptr<MetaData> RenderLayersProg::getMetaData() const
std::unique_ptr<MetaData> RenderLayersProg::getMetaData()
{
Scene *scene = this->getScene();
Render *re = (scene) ? RE_GetSceneRender(scene) : nullptr;

View File

@ -123,7 +123,7 @@ class RenderLayersProg : public NodeOperation {
void deinitExecution() override;
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
std::unique_ptr<MetaData> getMetaData() const override;
std::unique_ptr<MetaData> getMetaData() override;
};
class RenderLayersAOOperation : public RenderLayersProg {

View File

@ -48,7 +48,7 @@ inline void RotateOperation::ensureDegree()
{
if (!this->m_isDegreeSet) {
float degree[4];
this->m_degreeSocket->readSampled(degree, 0, 0, COM_PS_NEAREST);
this->m_degreeSocket->readSampled(degree, 0, 0, PixelSampler::Nearest);
double rad;
if (this->m_doDegree2RadConversion) {
rad = DEG2RAD((double)degree[0]);

View File

@ -28,7 +28,7 @@
BaseScaleOperation::BaseScaleOperation()
{
#ifdef USE_FORCE_BILINEAR
m_sampler = (int)COM_PS_BILINEAR;
m_sampler = (int)PixelSampler::Bilinear;
#else
m_sampler = -1;
#endif
@ -89,8 +89,8 @@ bool ScaleOperation::determineDependingAreaOfInterest(rcti *input,
float scaleX[4];
float scaleY[4];
this->m_inputXOperation->readSampled(scaleX, 0, 0, COM_PS_NEAREST);
this->m_inputYOperation->readSampled(scaleY, 0, 0, COM_PS_NEAREST);
this->m_inputXOperation->readSampled(scaleX, 0, 0, PixelSampler::Nearest);
this->m_inputYOperation->readSampled(scaleY, 0, 0, PixelSampler::Nearest);
const float scx = scaleX[0];
const float scy = scaleY[0];
@ -174,8 +174,8 @@ bool ScaleAbsoluteOperation::determineDependingAreaOfInterest(rcti *input,
float scaleX[4];
float scaleY[4];
this->m_inputXOperation->readSampled(scaleX, 0, 0, COM_PS_NEAREST);
this->m_inputYOperation->readSampled(scaleY, 0, 0, COM_PS_NEAREST);
this->m_inputXOperation->readSampled(scaleX, 0, 0, PixelSampler::Nearest);
this->m_inputYOperation->readSampled(scaleY, 0, 0, PixelSampler::Nearest);
const float scx = scaleX[0];
const float scy = scaleY[0];
@ -203,7 +203,7 @@ bool ScaleAbsoluteOperation::determineDependingAreaOfInterest(rcti *input,
// Absolute fixed size
ScaleFixedSizeOperation::ScaleFixedSizeOperation() : BaseScaleOperation()
{
this->addInputSocket(DataType::Color, COM_SC_NO_RESIZE);
this->addInputSocket(DataType::Color, ResizeMode::None);
this->addOutputSocket(DataType::Color);
this->setResolutionInputSocketIndex(0);
this->m_inputOperation = nullptr;

View File

@ -83,12 +83,12 @@ void *ScreenLensDistortionOperation::initializeTileData(rcti * /*rect*/)
if (!m_distortion_const) {
float result[4];
getInputSocketReader(1)->readSampled(result, 0, 0, COM_PS_NEAREST);
getInputSocketReader(1)->readSampled(result, 0, 0, PixelSampler::Nearest);
m_distortion = result[0];
}
if (!m_dispersion_const) {
float result[4];
getInputSocketReader(2)->readSampled(result, 0, 0, COM_PS_NEAREST);
getInputSocketReader(2)->readSampled(result, 0, 0, PixelSampler::Nearest);
m_dispersion = result[0];
}

View File

@ -25,7 +25,7 @@ SocketProxyOperation::SocketProxyOperation(DataType type, bool use_conversion)
this->addOutputSocket(type);
}
std::unique_ptr<MetaData> SocketProxyOperation::getMetaData() const
std::unique_ptr<MetaData> SocketProxyOperation::getMetaData()
{
return this->getInputSocket(0)->getReader()->getMetaData();
}

View File

@ -41,7 +41,7 @@ class SocketProxyOperation : public NodeOperation {
{
m_use_conversion = use_conversion;
}
std::unique_ptr<MetaData> getMetaData() const override;
std::unique_ptr<MetaData> getMetaData() override;
private:
bool m_use_conversion;

View File

@ -58,10 +58,10 @@ void SplitOperation::executePixelSampled(float output[4],
this->m_splitPercentage * this->getHeight() / 100.0f;
bool image1 = this->m_xSplit ? x > perc : y > perc;
if (image1) {
this->m_image1Input->readSampled(output, x, y, COM_PS_NEAREST);
this->m_image1Input->readSampled(output, x, y, PixelSampler::Nearest);
}
else {
this->m_image2Input->readSampled(output, x, y, COM_PS_NEAREST);
this->m_image2Input->readSampled(output, x, y, PixelSampler::Nearest);
}
}

View File

@ -24,7 +24,7 @@
TonemapOperation::TonemapOperation()
{
this->addInputSocket(DataType::Color, COM_SC_NO_RESIZE);
this->addInputSocket(DataType::Color, ResizeMode::None);
this->addOutputSocket(DataType::Color);
this->m_imageReader = nullptr;
this->m_data = nullptr;

View File

@ -56,7 +56,7 @@ void TranslateOperation::executePixelSampled(float output[4],
float originalXPos = x - this->getDeltaX();
float originalYPos = y - this->getDeltaY();
this->m_inputOperation->readSampled(output, originalXPos, originalYPos, COM_PS_BILINEAR);
this->m_inputOperation->readSampled(output, originalXPos, originalYPos, PixelSampler::Bilinear);
}
bool TranslateOperation::determineDependingAreaOfInterest(rcti *input,

View File

@ -54,9 +54,9 @@ class TranslateOperation : public NodeOperation {
{
if (!this->m_isDeltaSet) {
float tempDelta[4];
this->m_inputXOperation->readSampled(tempDelta, 0, 0, COM_PS_NEAREST);
this->m_inputXOperation->readSampled(tempDelta, 0, 0, PixelSampler::Nearest);
this->m_deltaX = tempDelta[0];
this->m_inputYOperation->readSampled(tempDelta, 0, 0, COM_PS_NEAREST);
this->m_inputYOperation->readSampled(tempDelta, 0, 0, PixelSampler::Nearest);
this->m_deltaY = tempDelta[0];
this->m_isDeltaSet = true;
}

View File

@ -25,11 +25,11 @@
VariableSizeBokehBlurOperation::VariableSizeBokehBlurOperation()
{
this->addInputSocket(DataType::Color);
this->addInputSocket(DataType::Color, COM_SC_NO_RESIZE); // do not resize the bokeh image.
this->addInputSocket(DataType::Color, ResizeMode::None); // do not resize the bokeh image.
this->addInputSocket(DataType::Value); // radius
#ifdef COM_DEFOCUS_SEARCH
this->addInputSocket(DataType::Color,
COM_SC_NO_RESIZE); // inverse search radius optimization structure.
ResizeMode::None); // inverse search radius optimization structure.
#endif
this->addOutputSocket(DataType::Color);
this->setComplex(true);
@ -278,7 +278,7 @@ bool VariableSizeBokehBlurOperation::determineDependingAreaOfInterest(
// InverseSearchRadiusOperation
InverseSearchRadiusOperation::InverseSearchRadiusOperation()
{
this->addInputSocket(DataType::Value, COM_SC_NO_RESIZE); // radius
this->addInputSocket(DataType::Value, ResizeMode::None); // radius
this->addOutputSocket(DataType::Color);
this->setComplex(true);
this->m_inputRadius = nullptr;
@ -319,7 +319,7 @@ void *InverseSearchRadiusOperation::initializeTileData(rcti *rect)
// for (int x2 = 0 ; x2 < DIVIDER ; x2 ++) {
// for (int y2 = 0 ; y2 < DIVIDER ; y2 ++) {
// this->m_inputRadius->read(temp, rx+x2, ry+y2, COM_PS_NEAREST);
// this->m_inputRadius->read(temp, rx+x2, ry+y2, PixelSampler::Nearest);
// if (radius < temp[0]) {
// radius = temp[0];
// maxx = x2;

View File

@ -98,12 +98,12 @@ void ViewerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
for (y = y1; y < y2 && (!breaked); y++) {
for (x = x1; x < x2; x++) {
this->m_imageInput->readSampled(&(buffer[offset4]), x, y, COM_PS_NEAREST);
this->m_imageInput->readSampled(&(buffer[offset4]), x, y, PixelSampler::Nearest);
if (this->m_useAlphaInput) {
this->m_alphaInput->readSampled(alpha, x, y, COM_PS_NEAREST);
this->m_alphaInput->readSampled(alpha, x, y, PixelSampler::Nearest);
buffer[offset4 + 3] = alpha[0];
}
this->m_depthInput->readSampled(depth, x, y, COM_PS_NEAREST);
this->m_depthInput->readSampled(depth, x, y, PixelSampler::Nearest);
depthbuffer[offset] = depth[0];
offset++;

View File

@ -97,7 +97,7 @@ void WriteBufferOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/
for (y = y1; y < y2 && (!breaked); y++) {
int offset4 = (y * memoryBuffer->getWidth() + x1) * num_channels;
for (x = x1; x < x2; x++) {
this->m_input->readSampled(&(buffer[offset4]), x, y, COM_PS_NEAREST);
this->m_input->readSampled(&(buffer[offset4]), x, y, PixelSampler::Nearest);
offset4 += num_channels;
}
if (isBraked()) {

Some files were not shown because too many files have changed in this diff Show More