Merge branch 'master' into sculpt-dev
This commit is contained in:
commit
a72cf784a7
|
@ -1763,8 +1763,20 @@ if(WITH_BLENDER)
|
|||
# internal and external library information first, for test linking
|
||||
add_subdirectory(source)
|
||||
elseif(WITH_CYCLES_STANDALONE)
|
||||
add_subdirectory(intern/glew-mx)
|
||||
add_subdirectory(intern/guardedalloc)
|
||||
add_subdirectory(intern/libc_compat)
|
||||
add_subdirectory(intern/numaapi)
|
||||
add_subdirectory(intern/sky)
|
||||
|
||||
add_subdirectory(intern/cycles)
|
||||
add_subdirectory(extern/clew)
|
||||
if(WITH_CYCLES_LOGGING)
|
||||
if(NOT WITH_SYSTEM_GFLAGS)
|
||||
add_subdirectory(extern/gflags)
|
||||
endif()
|
||||
add_subdirectory(extern/glog)
|
||||
endif()
|
||||
if(WITH_CUDA_DYNLOAD)
|
||||
add_subdirectory(extern/cuew)
|
||||
endif()
|
||||
|
@ -1845,6 +1857,8 @@ if(FIRST_RUN)
|
|||
info_cfg_option(WITH_OPENCOLORIO)
|
||||
info_cfg_option(WITH_OPENIMAGEDENOISE)
|
||||
info_cfg_option(WITH_OPENVDB)
|
||||
info_cfg_option(WITH_POTRACE)
|
||||
info_cfg_option(WITH_PUGIXML)
|
||||
info_cfg_option(WITH_QUADRIFLOW)
|
||||
info_cfg_option(WITH_TBB)
|
||||
info_cfg_option(WITH_USD)
|
||||
|
|
|
@ -44,6 +44,8 @@ set(WITH_OPENMP ON CACHE BOOL "" FORCE)
|
|||
set(WITH_OPENSUBDIV ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENVDB ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENVDB_BLOSC ON CACHE BOOL "" FORCE)
|
||||
set(WITH_POTRACE ON CACHE BOOL "" FORCE)
|
||||
set(WITH_PUGIXML ON CACHE BOOL "" FORCE)
|
||||
set(WITH_NANOVDB ON CACHE BOOL "" FORCE)
|
||||
set(WITH_POTRACE ON CACHE BOOL "" FORCE)
|
||||
set(WITH_PYTHON_INSTALL ON CACHE BOOL "" FORCE)
|
||||
|
|
|
@ -51,6 +51,8 @@ set(WITH_OPENIMAGEIO OFF CACHE BOOL "" FORCE)
|
|||
set(WITH_OPENMP OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENSUBDIV OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENVDB OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_POTRACE OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_PUGIXML OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_NANOVDB OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_QUADRIFLOW OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_SDL OFF CACHE BOOL "" FORCE)
|
||||
|
|
|
@ -45,6 +45,8 @@ set(WITH_OPENMP ON CACHE BOOL "" FORCE)
|
|||
set(WITH_OPENSUBDIV ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENVDB ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENVDB_BLOSC ON CACHE BOOL "" FORCE)
|
||||
set(WITH_POTRACE ON CACHE BOOL "" FORCE)
|
||||
set(WITH_PUGIXML ON CACHE BOOL "" FORCE)
|
||||
set(WITH_NANOVDB ON CACHE BOOL "" FORCE)
|
||||
set(WITH_POTRACE ON CACHE BOOL "" FORCE)
|
||||
set(WITH_PYTHON_INSTALL ON CACHE BOOL "" FORCE)
|
||||
|
|
|
@ -352,6 +352,11 @@ endif()
|
|||
|
||||
if(WITH_PUGIXML)
|
||||
find_package_wrapper(PugiXML)
|
||||
|
||||
if (NOT PUGIXML_FOUND)
|
||||
set(WITH_PUGIXML OFF)
|
||||
message(STATUS "PugiXML not found, disabling WITH_PUGIXML")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_OPENIMAGEIO)
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
# Standalone or with Blender
|
||||
if(NOT WITH_BLENDER AND WITH_CYCLES_STANDALONE)
|
||||
set(CYCLES_INSTALL_PATH "")
|
||||
set(CYCLES_INSTALL_PATH ${CMAKE_INSTALL_PREFIX})
|
||||
else()
|
||||
set(WITH_CYCLES_BLENDER ON)
|
||||
# WINDOWS_PYTHON_DEBUG needs to write into the user addons folder since it will
|
||||
|
|
|
@ -133,12 +133,12 @@ static void scene_init()
|
|||
|
||||
/* Camera width/height override? */
|
||||
if (!(options.width == 0 || options.height == 0)) {
|
||||
options.scene->camera->width = options.width;
|
||||
options.scene->camera->height = options.height;
|
||||
options.scene->camera->set_full_width(options.width);
|
||||
options.scene->camera->set_full_height(options.height);
|
||||
}
|
||||
else {
|
||||
options.width = options.scene->camera->width;
|
||||
options.height = options.scene->camera->height;
|
||||
options.width = options.scene->camera->get_full_width();
|
||||
options.height = options.scene->camera->get_full_height();
|
||||
}
|
||||
|
||||
/* Calculate Viewplane */
|
||||
|
@ -233,7 +233,7 @@ static void display()
|
|||
static void motion(int x, int y, int button)
|
||||
{
|
||||
if (options.interactive) {
|
||||
Transform matrix = options.session->scene->camera->matrix;
|
||||
Transform matrix = options.session->scene->camera->get_matrix();
|
||||
|
||||
/* Translate */
|
||||
if (button == 0) {
|
||||
|
@ -251,8 +251,8 @@ static void motion(int x, int y, int button)
|
|||
}
|
||||
|
||||
/* Update and Reset */
|
||||
options.session->scene->camera->matrix = matrix;
|
||||
options.session->scene->camera->need_update = true;
|
||||
options.session->scene->camera->set_matrix(matrix);
|
||||
options.session->scene->camera->need_flags_update = true;
|
||||
options.session->scene->camera->need_device_update = true;
|
||||
|
||||
options.session->reset(session_buffer_params(), options.session_params.samples);
|
||||
|
@ -266,10 +266,10 @@ static void resize(int width, int height)
|
|||
|
||||
if (options.session) {
|
||||
/* Update camera */
|
||||
options.session->scene->camera->width = width;
|
||||
options.session->scene->camera->height = height;
|
||||
options.session->scene->camera->set_full_width(options.width);
|
||||
options.session->scene->camera->set_full_height(options.height);
|
||||
options.session->scene->camera->compute_auto_viewplane();
|
||||
options.session->scene->camera->need_update = true;
|
||||
options.session->scene->camera->need_flags_update = true;
|
||||
options.session->scene->camera->need_device_update = true;
|
||||
|
||||
options.session->reset(session_buffer_params(), options.session_params.samples);
|
||||
|
@ -302,7 +302,7 @@ static void keyboard(unsigned char key)
|
|||
|
||||
/* Navigation */
|
||||
else if (options.interactive && (key == 'w' || key == 'a' || key == 's' || key == 'd')) {
|
||||
Transform matrix = options.session->scene->camera->matrix;
|
||||
Transform matrix = options.session->scene->camera->get_matrix();
|
||||
float3 translate;
|
||||
|
||||
if (key == 'w')
|
||||
|
@ -317,8 +317,8 @@ static void keyboard(unsigned char key)
|
|||
matrix = matrix * transform_translate(translate);
|
||||
|
||||
/* Update and Reset */
|
||||
options.session->scene->camera->matrix = matrix;
|
||||
options.session->scene->camera->need_update = true;
|
||||
options.session->scene->camera->set_matrix(matrix);
|
||||
options.session->scene->camera->need_flags_update = true;
|
||||
options.session->scene->camera->need_device_update = true;
|
||||
|
||||
options.session->reset(session_buffer_params(), options.session_params.samples);
|
||||
|
@ -345,10 +345,7 @@ static void keyboard(unsigned char key)
|
|||
break;
|
||||
}
|
||||
|
||||
options.session->scene->integrator->max_bounce = bounce;
|
||||
|
||||
/* Update and Reset */
|
||||
options.session->scene->integrator->need_update = true;
|
||||
options.session->scene->integrator->set_max_bounce(bounce);
|
||||
|
||||
options.session->reset(session_buffer_params(), options.session_params.samples);
|
||||
}
|
||||
|
|
|
@ -190,17 +190,18 @@ static void xml_read_camera(XMLReadState &state, xml_node node)
|
|||
{
|
||||
Camera *cam = state.scene->camera;
|
||||
|
||||
xml_read_int(&cam->width, node, "width");
|
||||
xml_read_int(&cam->height, node, "height");
|
||||
int width = -1, height = -1;
|
||||
xml_read_int(&width, node, "width");
|
||||
xml_read_int(&height, node, "height");
|
||||
|
||||
cam->full_width = cam->width;
|
||||
cam->full_height = cam->height;
|
||||
cam->set_full_width(width);
|
||||
cam->set_full_height(height);
|
||||
|
||||
xml_read_node(state, cam, node);
|
||||
|
||||
cam->matrix = state.tfm;
|
||||
cam->set_matrix(state.tfm);
|
||||
|
||||
cam->need_update = true;
|
||||
cam->need_flags_update = true;
|
||||
cam->update(state.scene);
|
||||
}
|
||||
|
||||
|
@ -338,11 +339,13 @@ static void xml_read_shader_graph(XMLReadState &state, Shader *shader, xml_node
|
|||
|
||||
if (node_name == "image_texture") {
|
||||
ImageTextureNode *img = (ImageTextureNode *)snode;
|
||||
img->filename = path_join(state.base, img->filename.string());
|
||||
ustring filename(path_join(state.base, img->get_filename().string()));
|
||||
img->set_filename(filename);
|
||||
}
|
||||
else if (node_name == "environment_texture") {
|
||||
EnvironmentTextureNode *env = (EnvironmentTextureNode *)snode;
|
||||
env->filename = path_join(state.base, env->filename.string());
|
||||
ustring filename(path_join(state.base, env->get_filename().string()));
|
||||
env->set_filename(filename);
|
||||
}
|
||||
|
||||
if (snode) {
|
||||
|
@ -384,8 +387,8 @@ static Mesh *xml_add_mesh(Scene *scene, const Transform &tfm)
|
|||
|
||||
/* create object*/
|
||||
Object *object = new Object();
|
||||
object->geometry = mesh;
|
||||
object->tfm = tfm;
|
||||
object->set_geometry(mesh);
|
||||
object->set_tfm(tfm);
|
||||
scene->objects.push_back(object);
|
||||
|
||||
return mesh;
|
||||
|
@ -395,7 +398,9 @@ static void xml_read_mesh(const XMLReadState &state, xml_node node)
|
|||
{
|
||||
/* add mesh */
|
||||
Mesh *mesh = xml_add_mesh(state.scene, state.tfm);
|
||||
mesh->used_shaders.push_back(state.shader);
|
||||
array<Node *> used_shaders = mesh->get_used_shaders();
|
||||
used_shaders.push_back_slow(state.shader);
|
||||
mesh->set_used_shaders(used_shaders);
|
||||
|
||||
/* read state */
|
||||
int shader = 0;
|
||||
|
@ -411,20 +416,24 @@ static void xml_read_mesh(const XMLReadState &state, xml_node node)
|
|||
xml_read_int_array(nverts, node, "nverts");
|
||||
|
||||
if (xml_equal_string(node, "subdivision", "catmull-clark")) {
|
||||
mesh->subdivision_type = Mesh::SUBDIVISION_CATMULL_CLARK;
|
||||
mesh->set_subdivision_type(Mesh::SUBDIVISION_CATMULL_CLARK);
|
||||
}
|
||||
else if (xml_equal_string(node, "subdivision", "linear")) {
|
||||
mesh->subdivision_type = Mesh::SUBDIVISION_LINEAR;
|
||||
mesh->set_subdivision_type(Mesh::SUBDIVISION_LINEAR);
|
||||
}
|
||||
|
||||
if (mesh->subdivision_type == Mesh::SUBDIVISION_NONE) {
|
||||
array<float3> P_array;
|
||||
P_array = P;
|
||||
|
||||
if (mesh->get_subdivision_type() == Mesh::SUBDIVISION_NONE) {
|
||||
/* create vertices */
|
||||
mesh->verts = P;
|
||||
|
||||
mesh->set_verts(P_array);
|
||||
|
||||
size_t num_triangles = 0;
|
||||
for (size_t i = 0; i < nverts.size(); i++)
|
||||
num_triangles += nverts[i] - 2;
|
||||
mesh->reserve_mesh(mesh->verts.size(), num_triangles);
|
||||
mesh->reserve_mesh(mesh->get_verts().size(), num_triangles);
|
||||
|
||||
/* create triangles */
|
||||
int index_offset = 0;
|
||||
|
@ -474,7 +483,7 @@ static void xml_read_mesh(const XMLReadState &state, xml_node node)
|
|||
}
|
||||
else {
|
||||
/* create vertices */
|
||||
mesh->verts = P;
|
||||
mesh->set_verts(P_array);
|
||||
|
||||
size_t num_ngons = 0;
|
||||
size_t num_corners = 0;
|
||||
|
@ -513,23 +522,20 @@ static void xml_read_mesh(const XMLReadState &state, xml_node node)
|
|||
}
|
||||
|
||||
/* setup subd params */
|
||||
if (!mesh->subd_params) {
|
||||
mesh->subd_params = new SubdParams(mesh);
|
||||
}
|
||||
SubdParams &sdparams = *mesh->subd_params;
|
||||
float dicing_rate = state.dicing_rate;
|
||||
xml_read_float(&dicing_rate, node, "dicing_rate");
|
||||
dicing_rate = std::max(0.1f, dicing_rate);
|
||||
|
||||
sdparams.dicing_rate = state.dicing_rate;
|
||||
xml_read_float(&sdparams.dicing_rate, node, "dicing_rate");
|
||||
sdparams.dicing_rate = std::max(0.1f, sdparams.dicing_rate);
|
||||
|
||||
sdparams.objecttoworld = state.tfm;
|
||||
mesh->set_subd_dicing_rate(dicing_rate);
|
||||
mesh->set_subd_objecttoworld(state.tfm);
|
||||
}
|
||||
|
||||
/* we don't yet support arbitrary attributes, for now add vertex
|
||||
* coordinates as generated coordinates if requested */
|
||||
if (mesh->need_attribute(state.scene, ATTR_STD_GENERATED)) {
|
||||
Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED);
|
||||
memcpy(attr->data_float3(), mesh->verts.data(), sizeof(float3) * mesh->verts.size());
|
||||
memcpy(
|
||||
attr->data_float3(), mesh->get_verts().data(), sizeof(float3) * mesh->get_verts().size());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -539,7 +545,7 @@ static void xml_read_light(XMLReadState &state, xml_node node)
|
|||
{
|
||||
Light *light = new Light();
|
||||
|
||||
light->shader = state.shader;
|
||||
light->set_shader(state.shader);
|
||||
xml_read_node(state, light, node);
|
||||
|
||||
state.scene->lights.push_back(light);
|
||||
|
|
|
@ -45,7 +45,7 @@ template<typename> struct is_array : public std::false_type {
|
|||
template<typename T> struct is_array<array<T>> : public std::true_type {
|
||||
};
|
||||
|
||||
/* Store the data set for an animation at every time points, or at the begining of the animation
|
||||
/* Store the data set for an animation at every time points, or at the beginning of the animation
|
||||
* for constant data.
|
||||
*
|
||||
* The data is supposed to be stored in chronological order, and is looked up using the current
|
||||
|
|
|
@ -661,15 +661,8 @@ void AttributeSet::update(AttributeSet &&new_attributes)
|
|||
{
|
||||
/* add or update old_attributes based on the new_attributes */
|
||||
foreach (Attribute &attr, new_attributes.attributes) {
|
||||
Attribute *nattr = nullptr;
|
||||
|
||||
if (attr.std != ATTR_STD_NONE) {
|
||||
nattr = add(attr.std, attr.name);
|
||||
}
|
||||
else {
|
||||
nattr = add(attr.name, attr.type, attr.element);
|
||||
}
|
||||
|
||||
Attribute *nattr = add(attr.name, attr.type, attr.element);
|
||||
nattr->std = attr.std;
|
||||
nattr->set_data_from(std::move(attr));
|
||||
}
|
||||
|
||||
|
|
|
@ -212,8 +212,8 @@ void Camera::compute_auto_viewplane()
|
|||
viewplane.top = 1.0f;
|
||||
}
|
||||
else {
|
||||
float aspect = (float)width / (float)height;
|
||||
if (width >= height) {
|
||||
float aspect = (float)full_width / (float)full_height;
|
||||
if (full_width >= full_height) {
|
||||
viewplane.left = -aspect;
|
||||
viewplane.right = aspect;
|
||||
viewplane.bottom = -1.0f;
|
||||
|
|
|
@ -43,18 +43,21 @@ rna_reverse_prop = BoolProperty(
|
|||
name="Reverse",
|
||||
description="Cycle backwards",
|
||||
default=False,
|
||||
options={'SKIP_SAVE'},
|
||||
)
|
||||
|
||||
rna_wrap_prop = BoolProperty(
|
||||
name="Wrap",
|
||||
description="Wrap back to the first/last values",
|
||||
default=False,
|
||||
options={'SKIP_SAVE'},
|
||||
)
|
||||
|
||||
rna_relative_prop = BoolProperty(
|
||||
name="Relative",
|
||||
description="Apply relative to the current value (delta)",
|
||||
default=False,
|
||||
options={'SKIP_SAVE'},
|
||||
)
|
||||
|
||||
rna_space_type_prop = EnumProperty(
|
||||
|
@ -228,6 +231,7 @@ class WM_OT_context_scale_int(Operator):
|
|||
name="Always Step",
|
||||
description="Always adjust the value by a minimum of 1 when 'value' is not 1.0",
|
||||
default=True,
|
||||
options={'SKIP_SAVE'},
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
|
@ -736,10 +740,12 @@ class WM_OT_context_modal_mouse(Operator):
|
|||
input_scale: FloatProperty(
|
||||
description="Scale the mouse movement by this value before applying the delta",
|
||||
default=0.01,
|
||||
options={'SKIP_SAVE'},
|
||||
)
|
||||
invert: BoolProperty(
|
||||
description="Invert the mouse input",
|
||||
default=False,
|
||||
options={'SKIP_SAVE'},
|
||||
)
|
||||
initial_x: IntProperty(options={'HIDDEN'})
|
||||
|
||||
|
@ -1727,6 +1733,7 @@ class WM_OT_tool_set_by_index(Operator):
|
|||
expand: BoolProperty(
|
||||
description="Include tool subgroups",
|
||||
default=True,
|
||||
options={'SKIP_SAVE'},
|
||||
)
|
||||
|
||||
as_fallback: BoolProperty(
|
||||
|
|
|
@ -107,6 +107,9 @@ class TIME_MT_editor_menus(Menu):
|
|||
text="Keying",
|
||||
)
|
||||
|
||||
# Add a separator to keep the popover button from aligning with the menu button.
|
||||
sub.separator(factor=0.4)
|
||||
|
||||
if horizontal:
|
||||
sub = row.row(align=True)
|
||||
|
||||
|
|
|
@ -1594,6 +1594,7 @@ class _defs_texture_paint:
|
|||
icon_prefix="brush.paint_texture.",
|
||||
type=bpy.types.Brush,
|
||||
attr="image_tool",
|
||||
cursor='PAINT_CROSS',
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -521,6 +521,9 @@ geometry_node_categories = [
|
|||
NodeItem("GeometryNodeRotatePoints"),
|
||||
NodeItem("GeometryNodeAlignRotationToVector"),
|
||||
]),
|
||||
GeometryNodeCategory("GEO_VOLUME", "Volume", items=[
|
||||
NodeItem("GeometryNodePointsToVolume"),
|
||||
]),
|
||||
GeometryNodeCategory("GEO_UTILITIES", "Utilities", items=[
|
||||
NodeItem("ShaderNodeMapRange"),
|
||||
NodeItem("ShaderNodeClamp"),
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# This script defines functions to be used directly in drivers expressions to
|
||||
# extend the builtin set of python functions.
|
||||
# This script defines functions to be used directly in driver expressions to
|
||||
# extend the built-in set of python functions.
|
||||
#
|
||||
# This can be executed on manually or set to 'Register' to
|
||||
# initialize thefunctions on file load.
|
||||
# initialize the functions on file load.
|
||||
|
||||
|
||||
# two sample functions
|
||||
|
@ -30,6 +30,6 @@ def slow_value(value, fac, uuid):
|
|||
|
||||
import bpy
|
||||
|
||||
# Add variable defined in this script into the drivers namespace.
|
||||
# Add functions defined in this script into the drivers namespace.
|
||||
bpy.app.driver_namespace["invert"] = invert
|
||||
bpy.app.driver_namespace["slow_value"] = slow_value
|
||||
|
|
|
@ -39,7 +39,7 @@ extern "C" {
|
|||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 3
|
||||
#define BLENDER_FILE_SUBVERSION 4
|
||||
|
||||
/* 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
|
||||
|
|
|
@ -46,9 +46,7 @@ typedef struct InstancedData {
|
|||
} InstancedData;
|
||||
|
||||
int BKE_geometry_set_instances(const struct GeometrySet *geometry_set,
|
||||
float (**r_positions)[3],
|
||||
float (**r_rotations)[3],
|
||||
float (**r_scales)[3],
|
||||
float (**r_transforms)[4][4],
|
||||
int **r_ids,
|
||||
struct InstancedData **r_instanced_data);
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <iostream>
|
||||
|
||||
#include "BLI_float3.hh"
|
||||
#include "BLI_float4x4.hh"
|
||||
#include "BLI_hash.hh"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_set.hh"
|
||||
|
@ -427,9 +428,7 @@ class PointCloudComponent : public GeometryComponent {
|
|||
/** A geometry component that stores instances. */
|
||||
class InstancesComponent : public GeometryComponent {
|
||||
private:
|
||||
blender::Vector<blender::float3> positions_;
|
||||
blender::Vector<blender::float3> rotations_;
|
||||
blender::Vector<blender::float3> scales_;
|
||||
blender::Vector<blender::float4x4> transforms_;
|
||||
blender::Vector<int> ids_;
|
||||
blender::Vector<InstancedData> instanced_data_;
|
||||
|
||||
|
@ -439,30 +438,14 @@ class InstancesComponent : public GeometryComponent {
|
|||
GeometryComponent *copy() const override;
|
||||
|
||||
void clear();
|
||||
void add_instance(Object *object,
|
||||
blender::float3 position,
|
||||
blender::float3 rotation = {0, 0, 0},
|
||||
blender::float3 scale = {1, 1, 1},
|
||||
const int id = -1);
|
||||
void add_instance(Collection *collection,
|
||||
blender::float3 position,
|
||||
blender::float3 rotation = {0, 0, 0},
|
||||
blender::float3 scale = {1, 1, 1},
|
||||
const int id = -1);
|
||||
void add_instance(InstancedData data,
|
||||
blender::float3 position,
|
||||
blender::float3 rotation,
|
||||
blender::float3 scale,
|
||||
const int id = -1);
|
||||
void add_instance(Object *object, blender::float4x4 transform, const int id = -1);
|
||||
void add_instance(Collection *collection, blender::float4x4 transform, const int id = -1);
|
||||
void add_instance(InstancedData data, blender::float4x4 transform, const int id = -1);
|
||||
|
||||
blender::Span<InstancedData> instanced_data() const;
|
||||
blender::Span<blender::float3> positions() const;
|
||||
blender::Span<blender::float3> rotations() const;
|
||||
blender::Span<blender::float3> scales() const;
|
||||
blender::Span<blender::float4x4> transforms() const;
|
||||
blender::Span<int> ids() const;
|
||||
blender::MutableSpan<blender::float3> positions();
|
||||
blender::MutableSpan<blender::float3> rotations();
|
||||
blender::MutableSpan<blender::float3> scales();
|
||||
blender::MutableSpan<blender::float4x4> transforms();
|
||||
int instances_amount() const;
|
||||
|
||||
bool is_empty() const final;
|
||||
|
|
|
@ -685,7 +685,7 @@ void nodeSetSocketAvailability(struct bNodeSocket *sock, bool is_available);
|
|||
int nodeSocketLinkLimit(const struct bNodeSocket *sock);
|
||||
|
||||
/* Node Clipboard */
|
||||
void BKE_node_clipboard_init(struct bNodeTree *ntree);
|
||||
void BKE_node_clipboard_init(const struct bNodeTree *ntree);
|
||||
void BKE_node_clipboard_clear(void);
|
||||
void BKE_node_clipboard_free(void);
|
||||
bool BKE_node_clipboard_validate(void);
|
||||
|
@ -706,8 +706,8 @@ extern const bNodeInstanceKey NODE_INSTANCE_KEY_BASE;
|
|||
extern const bNodeInstanceKey NODE_INSTANCE_KEY_NONE;
|
||||
|
||||
bNodeInstanceKey BKE_node_instance_key(bNodeInstanceKey parent_key,
|
||||
struct bNodeTree *ntree,
|
||||
struct bNode *node);
|
||||
const struct bNodeTree *ntree,
|
||||
const struct bNode *node);
|
||||
|
||||
bNodeInstanceHash *BKE_node_instance_hash_new(const char *info);
|
||||
void BKE_node_instance_hash_free(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp);
|
||||
|
@ -1362,6 +1362,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
|
|||
#define GEO_NODE_POINT_TRANSLATE 1019
|
||||
#define GEO_NODE_POINT_SCALE 1020
|
||||
#define GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE 1021
|
||||
#define GEO_NODE_POINTS_TO_VOLUME 1022
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -1943,9 +1943,6 @@ static void scene_collections_build_array(Collection *collection, void *data)
|
|||
|
||||
static void scene_collections_array(Scene *scene, Collection ***collections_array, int *tot)
|
||||
{
|
||||
Collection *collection;
|
||||
Collection **array;
|
||||
|
||||
*collections_array = NULL;
|
||||
*tot = 0;
|
||||
|
||||
|
@ -1953,7 +1950,7 @@ static void scene_collections_array(Scene *scene, Collection ***collections_arra
|
|||
return;
|
||||
}
|
||||
|
||||
collection = scene->master_collection;
|
||||
Collection *collection = scene->master_collection;
|
||||
BLI_assert(collection != NULL);
|
||||
scene_collection_callback(collection, scene_collections_count, tot);
|
||||
|
||||
|
@ -1961,7 +1958,8 @@ static void scene_collections_array(Scene *scene, Collection ***collections_arra
|
|||
return;
|
||||
}
|
||||
|
||||
*collections_array = array = MEM_mallocN(sizeof(Collection *) * (*tot), "CollectionArray");
|
||||
Collection **array = MEM_mallocN(sizeof(Collection *) * (*tot), "CollectionArray");
|
||||
*collections_array = array;
|
||||
scene_collection_callback(collection, scene_collections_build_array, &array);
|
||||
}
|
||||
|
||||
|
|
|
@ -212,9 +212,9 @@ static void layerFree_mdeformvert(void *data, int count, int size)
|
|||
/* copy just zeros in this case */
|
||||
static void layerCopy_bmesh_elem_py_ptr(const void *UNUSED(source), void *dest, int count)
|
||||
{
|
||||
int i, size = sizeof(void *);
|
||||
const int size = sizeof(void *);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
void **ptr = POINTER_OFFSET(dest, i * size);
|
||||
*ptr = NULL;
|
||||
}
|
||||
|
@ -253,15 +253,14 @@ static void layerInterp_mdeformvert(const void **sources,
|
|||
MDeformVert *dvert = dest;
|
||||
struct MDeformWeight_Link *dest_dwlink = NULL;
|
||||
struct MDeformWeight_Link *node;
|
||||
int i, j, totweight;
|
||||
|
||||
/* build a list of unique def_nrs for dest */
|
||||
totweight = 0;
|
||||
for (i = 0; i < count; i++) {
|
||||
int totweight = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
const MDeformVert *source = sources[i];
|
||||
float interp_weight = weights[i];
|
||||
|
||||
for (j = 0; j < source->totweight; j++) {
|
||||
for (int j = 0; j < source->totweight; j++) {
|
||||
MDeformWeight *dw = &source->dw[j];
|
||||
float weight = dw->weight * interp_weight;
|
||||
|
||||
|
@ -311,7 +310,8 @@ static void layerInterp_mdeformvert(const void **sources,
|
|||
|
||||
if (totweight) {
|
||||
dvert->totweight = totweight;
|
||||
for (i = 0, node = dest_dwlink; node; node = node->next, i++) {
|
||||
int i = 0;
|
||||
for (node = dest_dwlink; node; node = node->next, i++) {
|
||||
if (node->dw.weight > 1.0f) {
|
||||
node->dw.weight = 1.0f;
|
||||
}
|
||||
|
@ -416,18 +416,16 @@ static void layerInterp_tface(
|
|||
const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
|
||||
{
|
||||
MTFace *tf = dest;
|
||||
int i, j, k;
|
||||
float uv[4][2] = {{0.0f}};
|
||||
const float *sub_weight;
|
||||
|
||||
sub_weight = sub_weights;
|
||||
for (i = 0; i < count; i++) {
|
||||
const float *sub_weight = sub_weights;
|
||||
for (int i = 0; i < count; i++) {
|
||||
const float interp_weight = weights[i];
|
||||
const MTFace *src = sources[i];
|
||||
|
||||
for (j = 0; j < 4; j++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
if (sub_weights) {
|
||||
for (k = 0; k < 4; k++, sub_weight++) {
|
||||
for (int k = 0; k < 4; k++, sub_weight++) {
|
||||
madd_v2_v2fl(uv[j], src->uv[k], (*sub_weight) * interp_weight);
|
||||
}
|
||||
}
|
||||
|
@ -446,9 +444,8 @@ static void layerSwap_tface(void *data, const int *corner_indices)
|
|||
{
|
||||
MTFace *tf = data;
|
||||
float uv[4][2];
|
||||
int j;
|
||||
|
||||
for (j = 0; j < 4; j++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
const int source_index = corner_indices[j];
|
||||
copy_v2_v2(uv[j], tf->uv[source_index]);
|
||||
}
|
||||
|
@ -517,18 +514,16 @@ static void layerInterp_origspace_face(
|
|||
const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
|
||||
{
|
||||
OrigSpaceFace *osf = dest;
|
||||
int i, j, k;
|
||||
float uv[4][2] = {{0.0f}};
|
||||
const float *sub_weight;
|
||||
|
||||
sub_weight = sub_weights;
|
||||
for (i = 0; i < count; i++) {
|
||||
const float *sub_weight = sub_weights;
|
||||
for (int i = 0; i < count; i++) {
|
||||
const float interp_weight = weights[i];
|
||||
const OrigSpaceFace *src = sources[i];
|
||||
|
||||
for (j = 0; j < 4; j++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
if (sub_weights) {
|
||||
for (k = 0; k < 4; k++, sub_weight++) {
|
||||
for (int k = 0; k < 4; k++, sub_weight++) {
|
||||
madd_v2_v2fl(uv[j], src->uv[k], (*sub_weight) * interp_weight);
|
||||
}
|
||||
}
|
||||
|
@ -546,9 +541,8 @@ static void layerSwap_origspace_face(void *data, const int *corner_indices)
|
|||
{
|
||||
OrigSpaceFace *osf = data;
|
||||
float uv[4][2];
|
||||
int j;
|
||||
|
||||
for (j = 0; j < 4; j++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
copy_v2_v2(uv[j], osf->uv[corner_indices[j]]);
|
||||
}
|
||||
memcpy(osf->uv, uv, sizeof(osf->uv));
|
||||
|
@ -567,13 +561,11 @@ static void layerDefault_origspace_face(void *data, int count)
|
|||
static void layerSwap_mdisps(void *data, const int *ci)
|
||||
{
|
||||
MDisps *s = data;
|
||||
float(*d)[3] = NULL;
|
||||
int corners, cornersize, S;
|
||||
|
||||
if (s->disps) {
|
||||
int nverts = (ci[1] == 3) ? 4 : 3; /* silly way to know vertex count of face */
|
||||
corners = multires_mdisp_corners(s);
|
||||
cornersize = s->totdisp / corners;
|
||||
int corners = multires_mdisp_corners(s);
|
||||
int cornersize = s->totdisp / corners;
|
||||
|
||||
if (corners != nverts) {
|
||||
/* happens when face changed vertex count in edit mode
|
||||
|
@ -585,9 +577,9 @@ static void layerSwap_mdisps(void *data, const int *ci)
|
|||
return;
|
||||
}
|
||||
|
||||
d = MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisps swap");
|
||||
float(*d)[3] = MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisps swap");
|
||||
|
||||
for (S = 0; S < corners; S++) {
|
||||
for (int S = 0; S < corners; S++) {
|
||||
memcpy(d + cornersize * S, s->disps + cornersize * ci[S], sizeof(float[3]) * cornersize);
|
||||
}
|
||||
|
||||
|
@ -1128,9 +1120,8 @@ static void layerSwap_mcol(void *data, const int *corner_indices)
|
|||
{
|
||||
MCol *mcol = data;
|
||||
MCol col[4];
|
||||
int j;
|
||||
|
||||
for (j = 0; j < 4; j++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
col[j] = mcol[corner_indices[j]];
|
||||
}
|
||||
|
||||
|
@ -2064,13 +2055,13 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
|
|||
|
||||
void CustomData_update_typemap(CustomData *data)
|
||||
{
|
||||
int i, lasttype = -1;
|
||||
int lasttype = -1;
|
||||
|
||||
for (i = 0; i < CD_NUMTYPES; i++) {
|
||||
for (int i = 0; i < CD_NUMTYPES; i++) {
|
||||
data->typemap[i] = -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < data->totlayer; i++) {
|
||||
for (int i = 0; i < data->totlayer; i++) {
|
||||
const int type = data->layers[i].type;
|
||||
if (type != lasttype) {
|
||||
data->typemap[type] = i;
|
||||
|
@ -2097,18 +2088,16 @@ bool CustomData_merge(const struct CustomData *source,
|
|||
{
|
||||
/*const LayerTypeInfo *typeInfo;*/
|
||||
CustomDataLayer *layer, *newlayer;
|
||||
void *data;
|
||||
int i, type, lasttype = -1, lastactive = 0, lastrender = 0, lastclone = 0, lastmask = 0,
|
||||
flag = 0;
|
||||
int lasttype = -1, lastactive = 0, lastrender = 0, lastclone = 0, lastmask = 0;
|
||||
int number = 0, maxnumber = -1;
|
||||
bool changed = false;
|
||||
|
||||
for (i = 0; i < source->totlayer; i++) {
|
||||
for (int i = 0; i < source->totlayer; i++) {
|
||||
layer = &source->layers[i];
|
||||
/*typeInfo = layerType_getInfo(layer->type);*/ /*UNUSED*/
|
||||
|
||||
type = layer->type;
|
||||
flag = layer->flag;
|
||||
int type = layer->type;
|
||||
int flag = layer->flag;
|
||||
|
||||
if (type != lasttype) {
|
||||
number = 0;
|
||||
|
@ -2136,6 +2125,7 @@ bool CustomData_merge(const struct CustomData *source,
|
|||
continue;
|
||||
}
|
||||
|
||||
void *data;
|
||||
switch (alloctype) {
|
||||
case CD_ASSIGN:
|
||||
case CD_REFERENCE:
|
||||
|
@ -2518,8 +2508,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
|
|||
|
||||
/* Passing a layer-data to copy from with an alloctype that won't copy is
|
||||
* most likely a bug */
|
||||
BLI_assert(!layerdata || (alloctype == CD_ASSIGN) || (alloctype == CD_DUPLICATE) ||
|
||||
(alloctype == CD_REFERENCE));
|
||||
BLI_assert(!layerdata || ELEM(alloctype, CD_ASSIGN, CD_DUPLICATE, CD_REFERENCE));
|
||||
|
||||
if (!typeInfo->defaultname && CustomData_has_layer(data, type)) {
|
||||
return &data->layers[CustomData_get_layer_index(data, type)];
|
||||
|
@ -2616,10 +2605,9 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
|
|||
void *CustomData_add_layer(
|
||||
CustomData *data, int type, eCDAllocType alloctype, void *layerdata, int totelem)
|
||||
{
|
||||
CustomDataLayer *layer;
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
|
||||
|
||||
layer = customData_add_layer__internal(
|
||||
CustomDataLayer *layer = customData_add_layer__internal(
|
||||
data, type, alloctype, layerdata, totelem, typeInfo->defaultname);
|
||||
CustomData_update_typemap(data);
|
||||
|
||||
|
@ -2638,9 +2626,8 @@ void *CustomData_add_layer_named(CustomData *data,
|
|||
int totelem,
|
||||
const char *name)
|
||||
{
|
||||
CustomDataLayer *layer;
|
||||
|
||||
layer = customData_add_layer__internal(data, type, alloctype, layerdata, totelem, name);
|
||||
CustomDataLayer *layer = customData_add_layer__internal(
|
||||
data, type, alloctype, layerdata, totelem, name);
|
||||
CustomData_update_typemap(data);
|
||||
|
||||
if (layer) {
|
||||
|
@ -2828,12 +2815,10 @@ bool CustomData_is_referenced_layer(struct CustomData *data, int type)
|
|||
|
||||
void CustomData_free_temporary(CustomData *data, int totelem)
|
||||
{
|
||||
CustomDataLayer *layer;
|
||||
int i, j;
|
||||
bool changed = false;
|
||||
|
||||
for (i = 0, j = 0; i < data->totlayer; i++) {
|
||||
layer = &data->layers[i];
|
||||
CustomDataLayer *layer = &data->layers[i];
|
||||
|
||||
if (i != j) {
|
||||
data->layers[j] = data->layers[i];
|
||||
|
@ -3681,10 +3666,8 @@ void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data,
|
|||
|
||||
static void CustomData_bmesh_set_default_n(CustomData *data, void **block, int n)
|
||||
{
|
||||
const LayerTypeInfo *typeInfo;
|
||||
int offset = data->layers[n].offset;
|
||||
|
||||
typeInfo = layerType_getInfo(data->layers[n].type);
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[n].type);
|
||||
|
||||
if (typeInfo->set_default) {
|
||||
typeInfo->set_default(POINTER_OFFSET(*block, offset), 1);
|
||||
|
@ -4050,7 +4033,6 @@ void CustomData_bmesh_interp(CustomData *data,
|
|||
return;
|
||||
}
|
||||
|
||||
int i, j;
|
||||
void *source_buf[SOURCE_BUF_SIZE];
|
||||
const void **sources = (const void **)source_buf;
|
||||
|
||||
|
@ -4071,11 +4053,11 @@ void CustomData_bmesh_interp(CustomData *data,
|
|||
}
|
||||
|
||||
/* interpolates a layer at a time */
|
||||
for (i = 0; i < data->totlayer; i++) {
|
||||
for (int i = 0; i < data->totlayer; i++) {
|
||||
CustomDataLayer *layer = &data->layers[i];
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
|
||||
if (typeInfo->interp) {
|
||||
for (j = 0; j < count; j++) {
|
||||
for (int j = 0; j < count; j++) {
|
||||
sources[j] = POINTER_OFFSET(src_blocks[j], layer->offset);
|
||||
}
|
||||
CustomData_bmesh_interp_n(
|
||||
|
@ -4453,7 +4435,6 @@ bool CustomData_layer_validate(CustomDataLayer *layer, const uint totitems, cons
|
|||
|
||||
void CustomData_layers__print(CustomData *data)
|
||||
{
|
||||
|
||||
printf("{\n");
|
||||
|
||||
int i;
|
||||
|
@ -4508,10 +4489,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int
|
|||
{
|
||||
CustomDataExternal *external = data->external;
|
||||
CustomDataLayer *layer;
|
||||
CDataFile *cdf;
|
||||
CDataFileLayer *blay;
|
||||
char filename[FILE_MAX];
|
||||
const LayerTypeInfo *typeInfo;
|
||||
int update = 0;
|
||||
|
||||
if (!external) {
|
||||
|
@ -4520,7 +4498,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int
|
|||
|
||||
for (int i = 0; i < data->totlayer; i++) {
|
||||
layer = &data->layers[i];
|
||||
typeInfo = layerType_getInfo(layer->type);
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
|
||||
|
||||
if (!(mask & CD_TYPE_AS_MASK(layer->type))) {
|
||||
/* pass */
|
||||
|
@ -4539,7 +4517,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int
|
|||
|
||||
customdata_external_filename(filename, id, external);
|
||||
|
||||
cdf = cdf_create(CDF_TYPE_MESH);
|
||||
CDataFile *cdf = cdf_create(CDF_TYPE_MESH);
|
||||
if (!cdf_read_open(cdf, filename)) {
|
||||
cdf_free(cdf);
|
||||
CLOG_ERROR(&LOG, "Failed to read %s layer from %s.", layerType_getName(layer->type), filename);
|
||||
|
@ -4548,7 +4526,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int
|
|||
|
||||
for (int i = 0; i < data->totlayer; i++) {
|
||||
layer = &data->layers[i];
|
||||
typeInfo = layerType_getInfo(layer->type);
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
|
||||
|
||||
if (!(mask & CD_TYPE_AS_MASK(layer->type))) {
|
||||
/* pass */
|
||||
|
@ -4557,7 +4535,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int
|
|||
/* pass */
|
||||
}
|
||||
else if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->read) {
|
||||
blay = cdf_layer_find(cdf, layer->type, layer->name);
|
||||
CDataFileLayer *blay = cdf_layer_find(cdf, layer->type, layer->name);
|
||||
|
||||
if (blay) {
|
||||
if (cdf_read_layer(cdf, blay)) {
|
||||
|
@ -4584,10 +4562,6 @@ void CustomData_external_write(
|
|||
CustomData *data, ID *id, CustomDataMask mask, int totelem, int free)
|
||||
{
|
||||
CustomDataExternal *external = data->external;
|
||||
CustomDataLayer *layer;
|
||||
CDataFile *cdf;
|
||||
CDataFileLayer *blay;
|
||||
const LayerTypeInfo *typeInfo;
|
||||
int update = 0;
|
||||
char filename[FILE_MAX];
|
||||
|
||||
|
@ -4597,8 +4571,8 @@ void CustomData_external_write(
|
|||
|
||||
/* test if there is anything to write */
|
||||
for (int i = 0; i < data->totlayer; i++) {
|
||||
layer = &data->layers[i];
|
||||
typeInfo = layerType_getInfo(layer->type);
|
||||
CustomDataLayer *layer = &data->layers[i];
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
|
||||
|
||||
if (!(mask & CD_TYPE_AS_MASK(layer->type))) {
|
||||
/* pass */
|
||||
|
@ -4616,11 +4590,11 @@ void CustomData_external_write(
|
|||
CustomData_external_read(data, id, mask, totelem);
|
||||
customdata_external_filename(filename, id, external);
|
||||
|
||||
cdf = cdf_create(CDF_TYPE_MESH);
|
||||
CDataFile *cdf = cdf_create(CDF_TYPE_MESH);
|
||||
|
||||
for (int i = 0; i < data->totlayer; i++) {
|
||||
layer = &data->layers[i];
|
||||
typeInfo = layerType_getInfo(layer->type);
|
||||
CustomDataLayer *layer = &data->layers[i];
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
|
||||
|
||||
if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->filesize) {
|
||||
if (layer->flag & CD_FLAG_IN_MEMORY) {
|
||||
|
@ -4642,11 +4616,11 @@ void CustomData_external_write(
|
|||
|
||||
int i;
|
||||
for (i = 0; i < data->totlayer; i++) {
|
||||
layer = &data->layers[i];
|
||||
typeInfo = layerType_getInfo(layer->type);
|
||||
CustomDataLayer *layer = &data->layers[i];
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
|
||||
|
||||
if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) {
|
||||
blay = cdf_layer_find(cdf, layer->type, layer->name);
|
||||
CDataFileLayer *blay = cdf_layer_find(cdf, layer->type, layer->name);
|
||||
|
||||
if (cdf_write_layer(cdf, blay)) {
|
||||
if (typeInfo->write(cdf, layer->data, totelem)) {
|
||||
|
@ -4670,8 +4644,8 @@ void CustomData_external_write(
|
|||
}
|
||||
|
||||
for (i = 0; i < data->totlayer; i++) {
|
||||
layer = &data->layers[i];
|
||||
typeInfo = layerType_getInfo(layer->type);
|
||||
CustomDataLayer *layer = &data->layers[i];
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
|
||||
|
||||
if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) {
|
||||
if (free) {
|
||||
|
@ -4691,15 +4665,13 @@ void CustomData_external_add(
|
|||
CustomData *data, ID *UNUSED(id), int type, int UNUSED(totelem), const char *filename)
|
||||
{
|
||||
CustomDataExternal *external = data->external;
|
||||
CustomDataLayer *layer;
|
||||
int layer_index;
|
||||
|
||||
layer_index = CustomData_get_active_layer_index(data, type);
|
||||
int layer_index = CustomData_get_active_layer_index(data, type);
|
||||
if (layer_index == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
layer = &data->layers[layer_index];
|
||||
CustomDataLayer *layer = &data->layers[layer_index];
|
||||
|
||||
if (layer->flag & CD_FLAG_EXTERNAL) {
|
||||
return;
|
||||
|
@ -4823,8 +4795,6 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye
|
|||
cd_interp interp_cd = NULL;
|
||||
cd_copy copy_cd = NULL;
|
||||
|
||||
void *tmp_dst;
|
||||
|
||||
if (!sources) {
|
||||
/* Not supported here, abort. */
|
||||
return;
|
||||
|
@ -4841,7 +4811,7 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye
|
|||
copy_cd = type_info->copy;
|
||||
}
|
||||
|
||||
tmp_dst = MEM_mallocN(data_size, __func__);
|
||||
void *tmp_dst = MEM_mallocN(data_size, __func__);
|
||||
|
||||
if (count > 1 && !interp_cd) {
|
||||
if (data_flag) {
|
||||
|
@ -5104,6 +5074,10 @@ void CustomData_blend_write(BlendWriter *writer,
|
|||
const int *layer_data = layer->data;
|
||||
BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data);
|
||||
}
|
||||
else if (layer->type == CD_PROP_BOOL) {
|
||||
const bool *layer_data = layer->data;
|
||||
BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data);
|
||||
}
|
||||
else {
|
||||
const char *structname;
|
||||
int structnum;
|
||||
|
@ -5193,6 +5167,16 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count)
|
|||
|
||||
if (CustomData_verify_versions(data, i)) {
|
||||
BLO_read_data_address(reader, &layer->data);
|
||||
if (layer->data == NULL && count > 0 && layer->type == CD_PROP_BOOL) {
|
||||
/* Usually this should never happen, except when a custom data layer has not been written
|
||||
* to a file correctly. */
|
||||
CLOG_WARN(&LOG, "Reallocating custom data layer that was not saved correctly.");
|
||||
const LayerTypeInfo *info = layerType_getInfo(layer->type);
|
||||
layer->data = MEM_calloc_arrayN((size_t)count, info->size, layerType_getName(layer->type));
|
||||
if (info->set_default) {
|
||||
info->set_default(layer->data, count);
|
||||
}
|
||||
}
|
||||
if (layer->type == CD_MDISPS) {
|
||||
blend_read_mdisps(reader, count, layer->data, layer->flag & CD_FLAG_EXTERNAL);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "MEM_guardedalloc.h"
|
||||
|
||||
using blender::float3;
|
||||
using blender::float4x4;
|
||||
using blender::MutableSpan;
|
||||
using blender::Span;
|
||||
using blender::StringRef;
|
||||
|
@ -482,9 +483,7 @@ InstancesComponent::InstancesComponent() : GeometryComponent(GeometryComponentTy
|
|||
GeometryComponent *InstancesComponent::copy() const
|
||||
{
|
||||
InstancesComponent *new_component = new InstancesComponent();
|
||||
new_component->positions_ = positions_;
|
||||
new_component->rotations_ = rotations_;
|
||||
new_component->scales_ = scales_;
|
||||
new_component->transforms_ = transforms_;
|
||||
new_component->instanced_data_ = instanced_data_;
|
||||
return new_component;
|
||||
}
|
||||
|
@ -492,45 +491,29 @@ GeometryComponent *InstancesComponent::copy() const
|
|||
void InstancesComponent::clear()
|
||||
{
|
||||
instanced_data_.clear();
|
||||
positions_.clear();
|
||||
rotations_.clear();
|
||||
scales_.clear();
|
||||
transforms_.clear();
|
||||
}
|
||||
|
||||
void InstancesComponent::add_instance(Object *object,
|
||||
blender::float3 position,
|
||||
blender::float3 rotation,
|
||||
blender::float3 scale,
|
||||
const int id)
|
||||
void InstancesComponent::add_instance(Object *object, float4x4 transform, const int id)
|
||||
{
|
||||
InstancedData data;
|
||||
data.type = INSTANCE_DATA_TYPE_OBJECT;
|
||||
data.data.object = object;
|
||||
this->add_instance(data, position, rotation, scale, id);
|
||||
this->add_instance(data, transform, id);
|
||||
}
|
||||
|
||||
void InstancesComponent::add_instance(Collection *collection,
|
||||
blender::float3 position,
|
||||
blender::float3 rotation,
|
||||
blender::float3 scale,
|
||||
const int id)
|
||||
void InstancesComponent::add_instance(Collection *collection, float4x4 transform, const int id)
|
||||
{
|
||||
InstancedData data;
|
||||
data.type = INSTANCE_DATA_TYPE_COLLECTION;
|
||||
data.data.collection = collection;
|
||||
this->add_instance(data, position, rotation, scale, id);
|
||||
this->add_instance(data, transform, id);
|
||||
}
|
||||
|
||||
void InstancesComponent::add_instance(InstancedData data,
|
||||
blender::float3 position,
|
||||
blender::float3 rotation,
|
||||
blender::float3 scale,
|
||||
const int id)
|
||||
void InstancesComponent::add_instance(InstancedData data, float4x4 transform, const int id)
|
||||
{
|
||||
instanced_data_.append(data);
|
||||
positions_.append(position);
|
||||
rotations_.append(rotation);
|
||||
scales_.append(scale);
|
||||
transforms_.append(transform);
|
||||
ids_.append(id);
|
||||
}
|
||||
|
||||
|
@ -539,19 +522,9 @@ Span<InstancedData> InstancesComponent::instanced_data() const
|
|||
return instanced_data_;
|
||||
}
|
||||
|
||||
Span<float3> InstancesComponent::positions() const
|
||||
Span<float4x4> InstancesComponent::transforms() const
|
||||
{
|
||||
return positions_;
|
||||
}
|
||||
|
||||
Span<float3> InstancesComponent::rotations() const
|
||||
{
|
||||
return rotations_;
|
||||
}
|
||||
|
||||
Span<float3> InstancesComponent::scales() const
|
||||
{
|
||||
return scales_;
|
||||
return transforms_;
|
||||
}
|
||||
|
||||
Span<int> InstancesComponent::ids() const
|
||||
|
@ -559,33 +532,21 @@ Span<int> InstancesComponent::ids() const
|
|||
return ids_;
|
||||
}
|
||||
|
||||
MutableSpan<float3> InstancesComponent::positions()
|
||||
MutableSpan<float4x4> InstancesComponent::transforms()
|
||||
{
|
||||
return positions_;
|
||||
}
|
||||
|
||||
MutableSpan<float3> InstancesComponent::rotations()
|
||||
{
|
||||
return rotations_;
|
||||
}
|
||||
|
||||
MutableSpan<float3> InstancesComponent::scales()
|
||||
{
|
||||
return scales_;
|
||||
return transforms_;
|
||||
}
|
||||
|
||||
int InstancesComponent::instances_amount() const
|
||||
{
|
||||
const int size = instanced_data_.size();
|
||||
BLI_assert(positions_.size() == size);
|
||||
BLI_assert(rotations_.size() == size);
|
||||
BLI_assert(scales_.size() == size);
|
||||
BLI_assert(transforms_.size() == size);
|
||||
return size;
|
||||
}
|
||||
|
||||
bool InstancesComponent::is_empty() const
|
||||
{
|
||||
return positions_.size() == 0;
|
||||
return transforms_.size() == 0;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -684,9 +645,7 @@ bool BKE_geometry_set_has_instances(const GeometrySet *geometry_set)
|
|||
}
|
||||
|
||||
int BKE_geometry_set_instances(const GeometrySet *geometry_set,
|
||||
float (**r_positions)[3],
|
||||
float (**r_rotations)[3],
|
||||
float (**r_scales)[3],
|
||||
float (**r_transforms)[4][4],
|
||||
int **r_ids,
|
||||
InstancedData **r_instanced_data)
|
||||
{
|
||||
|
@ -694,9 +653,7 @@ int BKE_geometry_set_instances(const GeometrySet *geometry_set,
|
|||
if (component == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
*r_positions = (float(*)[3])component->positions().data();
|
||||
*r_rotations = (float(*)[3])component->rotations().data();
|
||||
*r_scales = (float(*)[3])component->scales().data();
|
||||
*r_transforms = (float(*)[4][4])component->transforms().data();
|
||||
*r_ids = (int *)component->ids().data();
|
||||
*r_instanced_data = (InstancedData *)component->instanced_data().data();
|
||||
*r_instanced_data = (InstancedData *)component->instanced_data().data();
|
||||
|
|
|
@ -92,11 +92,9 @@ IDProperty *IDP_NewIDPArray(const char *name)
|
|||
IDProperty *IDP_CopyIDPArray(const IDProperty *array, const int flag)
|
||||
{
|
||||
/* don't use MEM_dupallocN because this may be part of an array */
|
||||
IDProperty *narray, *tmp;
|
||||
|
||||
BLI_assert(array->type == IDP_IDPARRAY);
|
||||
|
||||
narray = MEM_mallocN(sizeof(IDProperty), __func__);
|
||||
IDProperty *narray = MEM_mallocN(sizeof(IDProperty), __func__);
|
||||
*narray = *array;
|
||||
|
||||
narray->data.pointer = MEM_dupallocN(array->data.pointer);
|
||||
|
@ -107,7 +105,7 @@ IDProperty *IDP_CopyIDPArray(const IDProperty *array, const int flag)
|
|||
* then free it. this makes for more maintainable
|
||||
* code than simply re-implementing the copy functions
|
||||
* in this loop.*/
|
||||
tmp = IDP_CopyProperty_ex(GETPROP(narray, i), flag);
|
||||
IDProperty *tmp = IDP_CopyProperty_ex(GETPROP(narray, i), flag);
|
||||
memcpy(GETPROP(narray, i), tmp, sizeof(IDProperty));
|
||||
MEM_freeN(tmp);
|
||||
}
|
||||
|
@ -131,15 +129,13 @@ static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user)
|
|||
/* shallow copies item */
|
||||
void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item)
|
||||
{
|
||||
IDProperty *old;
|
||||
|
||||
BLI_assert(prop->type == IDP_IDPARRAY);
|
||||
|
||||
if (index >= prop->len || index < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
old = GETPROP(prop, index);
|
||||
IDProperty *old = GETPROP(prop, index);
|
||||
if (item != old) {
|
||||
IDP_FreePropertyContent(old);
|
||||
|
||||
|
@ -164,8 +160,6 @@ void IDP_AppendArray(IDProperty *prop, IDProperty *item)
|
|||
|
||||
void IDP_ResizeIDPArray(IDProperty *prop, int newlen)
|
||||
{
|
||||
int newsize;
|
||||
|
||||
BLI_assert(prop->type == IDP_IDPARRAY);
|
||||
|
||||
/* first check if the array buffer size has room */
|
||||
|
@ -200,7 +194,7 @@ void IDP_ResizeIDPArray(IDProperty *prop, int newlen)
|
|||
* system realloc().
|
||||
* The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
|
||||
*/
|
||||
newsize = newlen;
|
||||
int newsize = newlen;
|
||||
newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
|
||||
prop->data.pointer = MEM_recallocN(prop->data.pointer, sizeof(IDProperty) * (size_t)newsize);
|
||||
prop->len = newlen;
|
||||
|
@ -218,9 +212,8 @@ static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr)
|
|||
/* bigger */
|
||||
IDProperty **array = newarr;
|
||||
IDPropertyTemplate val;
|
||||
int a;
|
||||
|
||||
for (a = prop->len; a < newlen; a++) {
|
||||
for (int a = prop->len; a < newlen; a++) {
|
||||
val.i = 0; /* silence MSVC warning about uninitialized var when debugging */
|
||||
array[a] = IDP_New(IDP_GROUP, &val, "IDP_ResizeArray group");
|
||||
}
|
||||
|
@ -228,9 +221,8 @@ static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr)
|
|||
else {
|
||||
/* smaller */
|
||||
IDProperty **array = prop->data.pointer;
|
||||
int a;
|
||||
|
||||
for (a = newlen; a < prop->len; a++) {
|
||||
for (int a = newlen; a < prop->len; a++) {
|
||||
IDP_FreeProperty(array[a]);
|
||||
}
|
||||
}
|
||||
|
@ -239,7 +231,6 @@ static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr)
|
|||
/*this function works for strings too!*/
|
||||
void IDP_ResizeArray(IDProperty *prop, int newlen)
|
||||
{
|
||||
int newsize;
|
||||
const bool is_grow = newlen >= prop->len;
|
||||
|
||||
/* first check if the array buffer size has room */
|
||||
|
@ -257,7 +248,7 @@ void IDP_ResizeArray(IDProperty *prop, int newlen)
|
|||
* system realloc().
|
||||
* The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
|
||||
*/
|
||||
newsize = newlen;
|
||||
int newsize = newlen;
|
||||
newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
|
||||
|
||||
if (is_grow == false) {
|
||||
|
@ -362,10 +353,8 @@ IDProperty *IDP_NewString(const char *st, const char *name, int maxlen)
|
|||
|
||||
static IDProperty *IDP_CopyString(const IDProperty *prop, const int flag)
|
||||
{
|
||||
IDProperty *newp;
|
||||
|
||||
BLI_assert(prop->type == IDP_STRING);
|
||||
newp = idp_generic_copy(prop, flag);
|
||||
IDProperty *newp = idp_generic_copy(prop, flag);
|
||||
|
||||
if (prop->data.pointer) {
|
||||
newp->data.pointer = MEM_dupallocN(prop->data.pointer);
|
||||
|
@ -379,10 +368,8 @@ static IDProperty *IDP_CopyString(const IDProperty *prop, const int flag)
|
|||
|
||||
void IDP_AssignString(IDProperty *prop, const char *st, int maxlen)
|
||||
{
|
||||
int stlen;
|
||||
|
||||
BLI_assert(prop->type == IDP_STRING);
|
||||
stlen = (int)strlen(st);
|
||||
int stlen = (int)strlen(st);
|
||||
if (maxlen > 0 && maxlen < stlen) {
|
||||
stlen = maxlen;
|
||||
}
|
||||
|
@ -400,11 +387,9 @@ void IDP_AssignString(IDProperty *prop, const char *st, int maxlen)
|
|||
|
||||
void IDP_ConcatStringC(IDProperty *prop, const char *st)
|
||||
{
|
||||
int newlen;
|
||||
|
||||
BLI_assert(prop->type == IDP_STRING);
|
||||
|
||||
newlen = prop->len + (int)strlen(st);
|
||||
int newlen = prop->len + (int)strlen(st);
|
||||
/* we have to remember that prop->len includes the null byte for strings.
|
||||
* so there's no need to add +1 to the resize function.*/
|
||||
IDP_ResizeArray(prop, newlen);
|
||||
|
@ -413,13 +398,11 @@ void IDP_ConcatStringC(IDProperty *prop, const char *st)
|
|||
|
||||
void IDP_ConcatString(IDProperty *str1, IDProperty *append)
|
||||
{
|
||||
int newlen;
|
||||
|
||||
BLI_assert(append->type == IDP_STRING);
|
||||
|
||||
/* since ->len for strings includes the NULL byte, we have to subtract one or
|
||||
* we'll get an extra null byte after each concatenation operation.*/
|
||||
newlen = str1->len + append->len - 1;
|
||||
int newlen = str1->len + append->len - 1;
|
||||
IDP_ResizeArray(str1, newlen);
|
||||
strcat(str1->data.pointer, append->data.pointer);
|
||||
}
|
||||
|
@ -440,10 +423,8 @@ void IDP_FreeString(IDProperty *prop)
|
|||
|
||||
static IDProperty *IDP_CopyID(const IDProperty *prop, const int flag)
|
||||
{
|
||||
IDProperty *newp;
|
||||
|
||||
BLI_assert(prop->type == IDP_ID);
|
||||
newp = idp_generic_copy(prop, flag);
|
||||
IDProperty *newp = idp_generic_copy(prop, flag);
|
||||
|
||||
newp->data.pointer = prop->data.pointer;
|
||||
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
|
||||
|
@ -479,14 +460,12 @@ void IDP_AssignID(IDProperty *prop, ID *id, const int flag)
|
|||
*/
|
||||
static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag)
|
||||
{
|
||||
IDProperty *newp, *link;
|
||||
|
||||
BLI_assert(prop->type == IDP_GROUP);
|
||||
newp = idp_generic_copy(prop, flag);
|
||||
IDProperty *newp = idp_generic_copy(prop, flag);
|
||||
newp->len = prop->len;
|
||||
newp->subtype = prop->subtype;
|
||||
|
||||
for (link = prop->data.group.first; link; link = link->next) {
|
||||
LISTBASE_FOREACH (IDProperty *, link, &prop->data.group) {
|
||||
BLI_addtail(&newp->data.group, IDP_CopyProperty_ex(link, flag));
|
||||
}
|
||||
|
||||
|
@ -497,13 +476,11 @@ static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag)
|
|||
* When values name and types match, copy the values, else ignore */
|
||||
void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src)
|
||||
{
|
||||
IDProperty *other, *prop;
|
||||
|
||||
BLI_assert(dest->type == IDP_GROUP);
|
||||
BLI_assert(src->type == IDP_GROUP);
|
||||
|
||||
for (prop = src->data.group.first; prop; prop = prop->next) {
|
||||
other = BLI_findstring(&dest->data.group, prop->name, offsetof(IDProperty, name));
|
||||
LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) {
|
||||
IDProperty *other = BLI_findstring(&dest->data.group, prop->name, offsetof(IDProperty, name));
|
||||
if (other && prop->type == other->type) {
|
||||
switch (prop->type) {
|
||||
case IDP_INT:
|
||||
|
@ -526,12 +503,9 @@ void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src)
|
|||
|
||||
void IDP_SyncGroupTypes(IDProperty *dest, const IDProperty *src, const bool do_arraylen)
|
||||
{
|
||||
IDProperty *prop_dst, *prop_dst_next;
|
||||
const IDProperty *prop_src;
|
||||
|
||||
for (prop_dst = dest->data.group.first; prop_dst; prop_dst = prop_dst_next) {
|
||||
prop_dst_next = prop_dst->next;
|
||||
if ((prop_src = IDP_GetPropertyFromGroup((IDProperty *)src, prop_dst->name))) {
|
||||
LISTBASE_FOREACH_MUTABLE (IDProperty *, prop_dst, &src->data.group) {
|
||||
const IDProperty *prop_src = IDP_GetPropertyFromGroup((IDProperty *)src, prop_dst->name);
|
||||
if (prop_src != NULL) {
|
||||
/* check of we should replace? */
|
||||
if ((prop_dst->type != prop_src->type || prop_dst->subtype != prop_src->subtype) ||
|
||||
(do_arraylen && ELEM(prop_dst->type, IDP_ARRAY, IDP_IDPARRAY) &&
|
||||
|
@ -554,12 +528,11 @@ void IDP_SyncGroupTypes(IDProperty *dest, const IDProperty *src, const bool do_a
|
|||
*/
|
||||
void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src)
|
||||
{
|
||||
IDProperty *loop, *prop;
|
||||
|
||||
BLI_assert(dest->type == IDP_GROUP);
|
||||
BLI_assert(src->type == IDP_GROUP);
|
||||
|
||||
for (prop = src->data.group.first; prop; prop = prop->next) {
|
||||
LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) {
|
||||
IDProperty *loop;
|
||||
for (loop = dest->data.group.first; loop; loop = loop->next) {
|
||||
if (STREQ(loop->name, prop->name)) {
|
||||
BLI_insertlinkreplace(&dest->data.group, loop, IDP_CopyProperty(prop));
|
||||
|
@ -612,13 +585,11 @@ void IDP_MergeGroup_ex(IDProperty *dest,
|
|||
const bool do_overwrite,
|
||||
const int flag)
|
||||
{
|
||||
IDProperty *prop;
|
||||
|
||||
BLI_assert(dest->type == IDP_GROUP);
|
||||
BLI_assert(src->type == IDP_GROUP);
|
||||
|
||||
if (do_overwrite) {
|
||||
for (prop = src->data.group.first; prop; prop = prop->next) {
|
||||
LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) {
|
||||
if (prop->type == IDP_GROUP) {
|
||||
IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
|
||||
|
||||
|
@ -633,7 +604,7 @@ void IDP_MergeGroup_ex(IDProperty *dest,
|
|||
}
|
||||
}
|
||||
else {
|
||||
for (prop = src->data.group.first; prop; prop = prop->next) {
|
||||
LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) {
|
||||
IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
|
||||
if (prop_exist != NULL) {
|
||||
if (prop->type == IDP_GROUP) {
|
||||
|
@ -741,10 +712,9 @@ IDProperty *IDP_GetPropertyTypeFromGroup(const IDProperty *prop, const char *nam
|
|||
* direct data. */
|
||||
static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user)
|
||||
{
|
||||
IDProperty *loop;
|
||||
|
||||
BLI_assert(prop->type == IDP_GROUP);
|
||||
for (loop = prop->data.group.first; loop; loop = loop->next) {
|
||||
|
||||
LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
|
||||
IDP_FreePropertyContent_ex(loop, do_id_user);
|
||||
}
|
||||
BLI_freelistN(&prop->data.group);
|
||||
|
@ -863,14 +833,12 @@ bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is
|
|||
}
|
||||
return false;
|
||||
case IDP_GROUP: {
|
||||
IDProperty *link1, *link2;
|
||||
|
||||
if (is_strict && prop1->len != prop2->len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (link1 = prop1->data.group.first; link1; link1 = link1->next) {
|
||||
link2 = IDP_GetPropertyFromGroup(prop2, link1->name);
|
||||
LISTBASE_FOREACH (IDProperty *, link1, &prop1->data.group) {
|
||||
IDProperty *link2 = IDP_GetPropertyFromGroup(prop2, link1->name);
|
||||
|
||||
if (!IDP_EqualsProperties_ex(link1, link2, is_strict)) {
|
||||
return false;
|
||||
|
@ -1158,11 +1126,10 @@ static void IDP_WriteIDPArray(const IDProperty *prop, BlendWriter *writer)
|
|||
/*REMEMBER to set totalen to len in the linking code!!*/
|
||||
if (prop->data.pointer) {
|
||||
const IDProperty *array = prop->data.pointer;
|
||||
int a;
|
||||
|
||||
BLO_write_struct_array(writer, IDProperty, prop->len, array);
|
||||
|
||||
for (a = 0; a < prop->len; a++) {
|
||||
for (int a = 0; a < prop->len; a++) {
|
||||
IDP_WriteProperty_OnlyData(&array[a], writer);
|
||||
}
|
||||
}
|
||||
|
@ -1176,9 +1143,7 @@ static void IDP_WriteString(const IDProperty *prop, BlendWriter *writer)
|
|||
|
||||
static void IDP_WriteGroup(const IDProperty *prop, BlendWriter *writer)
|
||||
{
|
||||
IDProperty *loop;
|
||||
|
||||
for (loop = prop->data.group.first; loop; loop = loop->next) {
|
||||
LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
|
||||
IDP_BlendWrite(writer, loop);
|
||||
}
|
||||
}
|
||||
|
@ -1212,13 +1177,11 @@ static void IDP_DirectLinkProperty(IDProperty *prop, BlendDataReader *reader);
|
|||
|
||||
static void IDP_DirectLinkIDPArray(IDProperty *prop, BlendDataReader *reader)
|
||||
{
|
||||
IDProperty *array;
|
||||
|
||||
/* since we didn't save the extra buffer, set totallen to len */
|
||||
prop->totallen = prop->len;
|
||||
BLO_read_data_address(reader, &prop->data.pointer);
|
||||
|
||||
array = (IDProperty *)prop->data.pointer;
|
||||
IDProperty *array = (IDProperty *)prop->data.pointer;
|
||||
|
||||
/* note!, idp-arrays didn't exist in 2.4x, so the pointer will be cleared
|
||||
* there's not really anything we can do to correct this, at least don't crash */
|
||||
|
@ -1234,14 +1197,12 @@ static void IDP_DirectLinkIDPArray(IDProperty *prop, BlendDataReader *reader)
|
|||
|
||||
static void IDP_DirectLinkArray(IDProperty *prop, BlendDataReader *reader)
|
||||
{
|
||||
IDProperty **array;
|
||||
|
||||
/* since we didn't save the extra buffer, set totallen to len */
|
||||
prop->totallen = prop->len;
|
||||
|
||||
if (prop->subtype == IDP_GROUP) {
|
||||
BLO_read_pointer_array(reader, &prop->data.pointer);
|
||||
array = prop->data.pointer;
|
||||
IDProperty **array = prop->data.pointer;
|
||||
|
||||
for (int i = 0; i < prop->len; i++) {
|
||||
IDP_DirectLinkProperty(array[i], reader);
|
||||
|
@ -1266,12 +1227,11 @@ static void IDP_DirectLinkString(IDProperty *prop, BlendDataReader *reader)
|
|||
static void IDP_DirectLinkGroup(IDProperty *prop, BlendDataReader *reader)
|
||||
{
|
||||
ListBase *lb = &prop->data.group;
|
||||
IDProperty *loop;
|
||||
|
||||
BLO_read_list(reader, lb);
|
||||
|
||||
/*Link child id properties now*/
|
||||
for (loop = prop->data.group.first; loop; loop = loop->next) {
|
||||
LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
|
||||
IDP_DirectLinkProperty(loop, reader);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -422,7 +422,7 @@ static int lib_override_linked_group_tag_cb(LibraryIDLinkCallbackData *cb_data)
|
|||
return IDWALK_RET_NOP;
|
||||
}
|
||||
|
||||
/* Tag all IDs in dependency relationships whithin an override hierarchy/group.
|
||||
/* Tag all IDs in dependency relationships within an override hierarchy/group.
|
||||
*
|
||||
* Note: this is typically called to complete `lib_override_linked_group_tag()`.
|
||||
* Note: BMain's relations mapping won't be valid anymore after that call.
|
||||
|
@ -464,8 +464,8 @@ static bool lib_override_hierarchy_dependencies_recursive_tag(Main *bmain,
|
|||
|
||||
/* This will tag at least all 'boundary' linked IDs for a potential override group.
|
||||
*
|
||||
* Note that you will then need to call `lib_override_hierarchy_dependencies_recursive_tag` to
|
||||
* complete tagging of all dependencies whitin theoverride group.
|
||||
* Note that you will then need to call #lib_override_hierarchy_dependencies_recursive_tag to
|
||||
* complete tagging of all dependencies within the override group.
|
||||
*
|
||||
* We currently only consider Collections and Objects (that are not used as bone shapes) as valid
|
||||
* boundary IDs to define an override group.
|
||||
|
@ -483,7 +483,7 @@ static void lib_override_linked_group_tag(Main *bmain,
|
|||
BKE_library_foreach_ID_link(
|
||||
bmain, id, lib_override_linked_group_tag_cb, &data, IDWALK_READONLY | IDWALK_RECURSE);
|
||||
|
||||
/* Then, we remove (untag) bone shape objects, you shall never want to directly/explicitely
|
||||
/* Then, we remove (untag) bone shape objects, you shall never want to directly/explicitly
|
||||
* override those. */
|
||||
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
|
||||
if (ob->type == OB_ARMATURE && ob->pose != NULL && (ob->id.tag & tag)) {
|
||||
|
@ -559,8 +559,8 @@ static int lib_override_local_group_tag_cb(LibraryIDLinkCallbackData *cb_data)
|
|||
|
||||
/* This will tag at least all 'boundary' linked IDs for a potential override group.
|
||||
*
|
||||
* Note that you will then need to call `lib_override_hierarchy_dependencies_recursive_tag` to
|
||||
* complete tagging of all dependencies whitin theoverride group.
|
||||
* Note that you will then need to call #lib_override_hierarchy_dependencies_recursive_tag to
|
||||
* complete tagging of all dependencies within the override group.
|
||||
*
|
||||
* We currently only consider Collections and Objects (that are not used as bone shapes) as valid
|
||||
* boundary IDs to define an override group.
|
||||
|
|
|
@ -781,7 +781,7 @@ static DerivedMesh *subsurf_dm_create_local(Scene *scene,
|
|||
smd.levels = smd.renderLevels = lvl;
|
||||
smd.quality = 3;
|
||||
if (!is_plain_uv) {
|
||||
smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS;
|
||||
smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES;
|
||||
}
|
||||
else {
|
||||
smd.uv_smooth = SUBSURF_UV_SMOOTH_NONE;
|
||||
|
|
|
@ -3574,7 +3574,7 @@ typedef struct bNodeClipboard {
|
|||
|
||||
static bNodeClipboard node_clipboard = {{NULL}};
|
||||
|
||||
void BKE_node_clipboard_init(struct bNodeTree *ntree)
|
||||
void BKE_node_clipboard_init(const struct bNodeTree *ntree)
|
||||
{
|
||||
node_clipboard.type = ntree->type;
|
||||
}
|
||||
|
@ -3718,11 +3718,11 @@ static bNodeInstanceKey node_hash_int_str(bNodeInstanceKey hash, const char *str
|
|||
return hash;
|
||||
}
|
||||
|
||||
bNodeInstanceKey BKE_node_instance_key(bNodeInstanceKey parent_key, bNodeTree *ntree, bNode *node)
|
||||
bNodeInstanceKey BKE_node_instance_key(bNodeInstanceKey parent_key,
|
||||
const bNodeTree *ntree,
|
||||
const bNode *node)
|
||||
{
|
||||
bNodeInstanceKey key;
|
||||
|
||||
key = node_hash_int_str(parent_key, ntree->id.name + 2);
|
||||
bNodeInstanceKey key = node_hash_int_str(parent_key, ntree->id.name + 2);
|
||||
|
||||
if (node) {
|
||||
key = node_hash_int_str(key, node->name);
|
||||
|
@ -4750,6 +4750,7 @@ static void registerGeometryNodes(void)
|
|||
register_node_type_geo_point_rotate();
|
||||
register_node_type_geo_align_rotation_to_vector();
|
||||
register_node_type_geo_sample_texture();
|
||||
register_node_type_geo_points_to_volume();
|
||||
}
|
||||
|
||||
static void registerFunctionNodes(void)
|
||||
|
|
|
@ -813,40 +813,26 @@ static const DupliGenerator gen_dupli_verts_pointcloud = {
|
|||
|
||||
static void make_duplis_instances_component(const DupliContext *ctx)
|
||||
{
|
||||
float(*positions)[3];
|
||||
float(*rotations)[3];
|
||||
float(*scales)[3];
|
||||
float(*instance_offset_matrices)[4][4];
|
||||
int *ids;
|
||||
InstancedData *instanced_data;
|
||||
const int amount = BKE_geometry_set_instances(ctx->object->runtime.geometry_set_eval,
|
||||
&positions,
|
||||
&rotations,
|
||||
&scales,
|
||||
&ids,
|
||||
&instanced_data);
|
||||
const int amount = BKE_geometry_set_instances(
|
||||
ctx->object->runtime.geometry_set_eval, &instance_offset_matrices, &ids, &instanced_data);
|
||||
|
||||
for (int i = 0; i < amount; i++) {
|
||||
InstancedData *data = &instanced_data[i];
|
||||
|
||||
float scale_matrix[4][4];
|
||||
size_to_mat4(scale_matrix, scales[i]);
|
||||
float rotation_matrix[4][4];
|
||||
eul_to_mat4(rotation_matrix, rotations[i]);
|
||||
float instance_offset_matrix[4][4];
|
||||
mul_m4_m4m4(instance_offset_matrix, rotation_matrix, scale_matrix);
|
||||
copy_v3_v3(instance_offset_matrix[3], positions[i]);
|
||||
|
||||
const int id = ids[i] != -1 ? ids[i] : i;
|
||||
|
||||
if (data->type == INSTANCE_DATA_TYPE_OBJECT) {
|
||||
Object *object = data->data.object;
|
||||
if (object != NULL) {
|
||||
float matrix[4][4];
|
||||
mul_m4_m4m4(matrix, ctx->object->obmat, instance_offset_matrix);
|
||||
mul_m4_m4m4(matrix, ctx->object->obmat, instance_offset_matrices[i]);
|
||||
make_dupli(ctx, object, matrix, id);
|
||||
|
||||
float space_matrix[4][4];
|
||||
mul_m4_m4m4(space_matrix, instance_offset_matrix, object->imat);
|
||||
mul_m4_m4m4(space_matrix, instance_offset_matrices[i], object->imat);
|
||||
mul_m4_m4_pre(space_matrix, ctx->object->obmat);
|
||||
make_recursive_duplis(ctx, object, space_matrix, id);
|
||||
}
|
||||
|
@ -857,7 +843,7 @@ static void make_duplis_instances_component(const DupliContext *ctx)
|
|||
float collection_matrix[4][4];
|
||||
unit_m4(collection_matrix);
|
||||
sub_v3_v3(collection_matrix[3], collection->instance_offset);
|
||||
mul_m4_m4_pre(collection_matrix, instance_offset_matrix);
|
||||
mul_m4_m4_pre(collection_matrix, instance_offset_matrices[i]);
|
||||
mul_m4_m4_pre(collection_matrix, ctx->object->obmat);
|
||||
|
||||
eEvaluationMode mode = DEG_get_mode(ctx->depsgraph);
|
||||
|
|
|
@ -586,7 +586,7 @@ UndoPushReturn BKE_undosys_step_push_with_type(UndoStack *ustack,
|
|||
BLI_strncpy(us->name, name, sizeof(us->name));
|
||||
}
|
||||
us->type = ut;
|
||||
/* True by default, code needs to explicitely set it to false if necessary. */
|
||||
/* True by default, code needs to explicitly set it to false if necessary. */
|
||||
us->use_old_bmain_data = true;
|
||||
/* Initialized, not added yet. */
|
||||
|
||||
|
|
|
@ -45,6 +45,17 @@ struct float4x4 {
|
|||
return &values[0][0];
|
||||
}
|
||||
|
||||
using c_style_float4x4 = float[4][4];
|
||||
c_style_float4x4 &ptr()
|
||||
{
|
||||
return values;
|
||||
}
|
||||
|
||||
const c_style_float4x4 &ptr() const
|
||||
{
|
||||
return values;
|
||||
}
|
||||
|
||||
friend float4x4 operator*(const float4x4 &a, const float4x4 &b)
|
||||
{
|
||||
float4x4 result;
|
||||
|
|
|
@ -1505,7 +1505,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
|||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 292, 10)) {
|
||||
if (!DNA_struct_find(fd->filesdna, "NodeSetAlpha")) {
|
||||
LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
|
||||
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
|
||||
if (ntree->type != NTREE_COMPOSIT) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1518,6 +1518,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
|||
node->storage = storage;
|
||||
}
|
||||
}
|
||||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
|
@ -1636,6 +1637,21 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
|||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 293, 4)) {
|
||||
/* Add support for all operations to the "Attribute Math" node. */
|
||||
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
|
||||
if (ntree->type == NTREE_GEOMETRY) {
|
||||
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
|
||||
if (node->type == GEO_NODE_ATTRIBUTE_MATH) {
|
||||
NodeAttributeMath *data = (NodeAttributeMath *)node->storage;
|
||||
data->input_type_c = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
/**
|
||||
* Versioning code until next subversion bump goes here.
|
||||
*
|
||||
|
|
|
@ -68,7 +68,8 @@ class RenderLayersProg : public NodeOperation {
|
|||
/**
|
||||
* Determine the output resolution. The resolution is retrieved from the Renderer
|
||||
*/
|
||||
void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]);
|
||||
void determineResolution(unsigned int resolution[2],
|
||||
unsigned int preferredResolution[2]) override;
|
||||
|
||||
/**
|
||||
* retrieve the reference to the float buffer of the renderer.
|
||||
|
@ -118,9 +119,9 @@ class RenderLayersProg : public NodeOperation {
|
|||
{
|
||||
return this->m_viewName;
|
||||
}
|
||||
void initExecution();
|
||||
void deinitExecution();
|
||||
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
|
||||
void initExecution() override;
|
||||
void deinitExecution() override;
|
||||
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
|
||||
|
||||
std::unique_ptr<MetaData> getMetaData() const override;
|
||||
};
|
||||
|
|
|
@ -24,11 +24,11 @@ class SocketProxyOperation : public NodeOperation {
|
|||
public:
|
||||
SocketProxyOperation(DataType type, bool use_conversion);
|
||||
|
||||
bool isProxyOperation() const
|
||||
bool isProxyOperation() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool useDatatypeConversion() const
|
||||
bool useDatatypeConversion() const override
|
||||
{
|
||||
return m_use_conversion;
|
||||
}
|
||||
|
|
|
@ -137,6 +137,15 @@ static void workbench_studiolight_data_update(WORKBENCH_PrivateData *wpd, WORKBE
|
|||
wd->use_specular = workbench_is_specular_highlight_enabled(wpd);
|
||||
}
|
||||
|
||||
void workbench_private_data_alloc(WORKBENCH_StorageList *stl)
|
||||
{
|
||||
if (!stl->wpd) {
|
||||
stl->wpd = MEM_callocN(sizeof(*stl->wpd), __func__);
|
||||
stl->wpd->taa_sample_len_previous = -1;
|
||||
stl->wpd->view_updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
|
||||
{
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
|
|
|
@ -133,14 +133,14 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata)
|
|||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
RegionView3D *rv3d = draw_ctx->rv3d;
|
||||
View3D *v3d = draw_ctx->v3d;
|
||||
Scene *scene = draw_ctx->scene;
|
||||
|
||||
Object *camera;
|
||||
|
||||
if (v3d && rv3d) {
|
||||
camera = (rv3d->persp == RV3D_CAMOB) ? v3d->camera : NULL;
|
||||
}
|
||||
else {
|
||||
camera = scene->camera;
|
||||
camera = wpd->cam_original_ob;
|
||||
}
|
||||
|
||||
Camera *cam = camera != NULL ? camera->data : NULL;
|
||||
|
|
|
@ -53,12 +53,7 @@ void workbench_engine_init(void *ved)
|
|||
|
||||
workbench_shader_library_ensure();
|
||||
|
||||
if (!stl->wpd) {
|
||||
stl->wpd = MEM_callocN(sizeof(*stl->wpd), __func__);
|
||||
stl->wpd->taa_sample_len_previous = -1;
|
||||
stl->wpd->view_updated = true;
|
||||
}
|
||||
|
||||
workbench_private_data_alloc(stl);
|
||||
WORKBENCH_PrivateData *wpd = stl->wpd;
|
||||
workbench_private_data_init(wpd);
|
||||
workbench_update_world_ubo(wpd);
|
||||
|
|
|
@ -70,6 +70,7 @@ extern struct DrawEngineType draw_engine_workbench;
|
|||
#define OBJECT_ID_PASS_ENABLED(wpd) (OBJECT_OUTLINE_ENABLED(wpd) || CURVATURE_ENABLED(wpd))
|
||||
#define NORMAL_ENCODING_ENABLED() (true)
|
||||
|
||||
struct Object;
|
||||
struct RenderEngine;
|
||||
struct RenderLayer;
|
||||
struct rcti;
|
||||
|
@ -351,6 +352,9 @@ typedef struct WORKBENCH_PrivateData {
|
|||
float dof_rotation;
|
||||
float dof_ratio;
|
||||
|
||||
/* Camera override for rendering. */
|
||||
struct Object *cam_original_ob;
|
||||
|
||||
/** True if any volume needs to be rendered. */
|
||||
bool volumes_do;
|
||||
/** Convenience boolean. */
|
||||
|
@ -504,6 +508,7 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
|
|||
workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, WORKBENCH_DATATYPE_HAIR)
|
||||
|
||||
/* workbench_data.c */
|
||||
void workbench_private_data_alloc(WORKBENCH_StorageList *stl);
|
||||
void workbench_private_data_init(WORKBENCH_PrivateData *wpd);
|
||||
void workbench_update_world_ubo(WORKBENCH_PrivateData *wpd);
|
||||
void workbench_update_material_ubos(WORKBENCH_PrivateData *wpd);
|
||||
|
|
|
@ -175,6 +175,8 @@ void workbench_render(void *ved, RenderEngine *engine, RenderLayer *render_layer
|
|||
return;
|
||||
}
|
||||
|
||||
workbench_private_data_alloc(data->stl);
|
||||
data->stl->wpd->cam_original_ob = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
|
||||
workbench_engine_init(data);
|
||||
|
||||
workbench_cache_init(data);
|
||||
|
|
|
@ -1715,8 +1715,8 @@ void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
|
|||
|
||||
GPU_matrix_identity_set();
|
||||
GPU_matrix_identity_projection_set();
|
||||
|
||||
GPU_viewport_unbind_from_offscreen(render_viewport, ofs, do_color_management);
|
||||
const bool do_overlays = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0;
|
||||
GPU_viewport_unbind_from_offscreen(render_viewport, ofs, do_color_management, do_overlays);
|
||||
|
||||
if (draw_background) {
|
||||
/* Reset default. */
|
||||
|
|
|
@ -393,7 +393,11 @@ static void anim_channels_select_set(bAnimContext *ac,
|
|||
FCurve *fcu = (FCurve *)ale->data;
|
||||
|
||||
ACHANNEL_SET_FLAG(fcu, sel, FCURVE_SELECTED);
|
||||
fcu->flag &= ~FCURVE_ACTIVE;
|
||||
if ((fcu->flag & FCURVE_SELECTED) == 0) {
|
||||
/* Only erase the ACTIVE flag when deselecting. This ensures that "select all curves"
|
||||
* retains the currently active curve. */
|
||||
fcu->flag &= ~FCURVE_ACTIVE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ANIMTYPE_SHAPEKEY: {
|
||||
|
@ -1197,7 +1201,7 @@ static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, eRearrangeAn
|
|||
rearrange_animchannel_islands(
|
||||
&adt->nla_tracks, rearrange_func, mode, ANIMTYPE_NLATRACK, &anim_data_visible);
|
||||
|
||||
/* Add back non-local NLA tracks at the begining of the animation data's list. */
|
||||
/* Add back non-local NLA tracks at the beginning of the animation data's list. */
|
||||
if (!BLI_listbase_is_empty(&extracted_nonlocal_nla_tracks)) {
|
||||
BLI_assert(is_liboverride);
|
||||
((NlaTrack *)extracted_nonlocal_nla_tracks.last)->next = adt->nla_tracks.first;
|
||||
|
|
|
@ -124,29 +124,22 @@ static void draw_current_frame(const Scene *scene,
|
|||
|
||||
UI_draw_roundbox_corner_set(UI_CNR_ALL);
|
||||
|
||||
UI_draw_roundbox_3fv_alpha(
|
||||
&(const rctf){
|
||||
.xmin = frame_x - box_width / 2 + U.pixelsize / 2,
|
||||
.xmax = frame_x + box_width / 2 + U.pixelsize / 2,
|
||||
.ymin = scrub_region_rect->ymin + box_padding,
|
||||
.ymax = scrub_region_rect->ymax - box_padding,
|
||||
},
|
||||
true,
|
||||
4 * UI_DPI_FAC,
|
||||
bg_color,
|
||||
1.0f);
|
||||
float outline_color[4];
|
||||
UI_GetThemeColorShade4fv(TH_CFRAME, 5, outline_color);
|
||||
|
||||
UI_GetThemeColorShade4fv(TH_CFRAME, 5, bg_color);
|
||||
UI_draw_roundbox_aa(
|
||||
UI_draw_roundbox_4fv_ex(
|
||||
&(const rctf){
|
||||
.xmin = frame_x - box_width / 2 + U.pixelsize / 2,
|
||||
.xmax = frame_x + box_width / 2 + U.pixelsize / 2,
|
||||
.ymin = scrub_region_rect->ymin + box_padding,
|
||||
.ymax = scrub_region_rect->ymax - box_padding,
|
||||
},
|
||||
true,
|
||||
4 * UI_DPI_FAC,
|
||||
bg_color);
|
||||
bg_color,
|
||||
NULL,
|
||||
1.0f,
|
||||
outline_color,
|
||||
U.pixelsize,
|
||||
4 * UI_DPI_FAC);
|
||||
|
||||
uchar text_color[4];
|
||||
UI_GetThemeColor4ubv(TH_HEADER_TEXT_HI, text_color);
|
||||
|
|
|
@ -1154,8 +1154,8 @@ static int gpencil_points_from_stack(tGPDfill *tgpf)
|
|||
static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
|
||||
{
|
||||
ToolSettings *ts = tgpf->scene->toolsettings;
|
||||
const char *align_flag = &ts->gpencil_v3d_align;
|
||||
const bool is_depth = (bool)(*align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE));
|
||||
const char align_flag = ts->gpencil_v3d_align;
|
||||
const bool is_depth = (bool)(align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE));
|
||||
const bool is_camera = (bool)(ts->gp_sculpt.lock_axis == 0) &&
|
||||
(tgpf->rv3d->persp == RV3D_CAMOB) && (!is_depth);
|
||||
Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
|
||||
|
@ -1284,8 +1284,8 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
|
|||
gpencil_apply_parent_point(tgpf->depsgraph, tgpf->ob, tgpf->gpl, pt);
|
||||
}
|
||||
|
||||
/* if camera view, reproject flat to view to avoid perspective effect */
|
||||
if (is_camera) {
|
||||
/* If camera view or view projection, reproject flat to view to avoid perspective effect. */
|
||||
if ((align_flag & GP_PROJECT_VIEWSPACE) || is_camera) {
|
||||
ED_gpencil_project_stroke_to_view(tgpf->C, tgpf->gpl, gps);
|
||||
}
|
||||
|
||||
|
|
|
@ -1086,8 +1086,8 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
|
|||
gpencil_apply_parent_point(depsgraph, obact, gpl, pt);
|
||||
}
|
||||
|
||||
/* if camera view, reproject flat to view to avoid perspective effect */
|
||||
if (is_camera) {
|
||||
/* If camera view or view projection, reproject flat to view to avoid perspective effect. */
|
||||
if ((*p->align_flag & GP_PROJECT_VIEWSPACE) || is_camera) {
|
||||
ED_gpencil_project_stroke_to_view(p->C, p->gpl, gps);
|
||||
}
|
||||
}
|
||||
|
@ -1235,8 +1235,8 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
|
|||
gpencil_reproject_toplane(p, gps);
|
||||
/* change position relative to parent object */
|
||||
gpencil_apply_parent(depsgraph, obact, gpl, gps);
|
||||
/* if camera view, reproject flat to view to avoid perspective effect */
|
||||
if (is_camera) {
|
||||
/* If camera view or view projection, reproject flat to view to avoid perspective effect. */
|
||||
if ((*p->align_flag & GP_PROJECT_VIEWSPACE) || is_camera) {
|
||||
ED_gpencil_project_stroke_to_view(p->C, p->gpl, gps);
|
||||
}
|
||||
|
||||
|
|
|
@ -715,8 +715,8 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
|
|||
bGPDstroke *gps = tgpi->gpf->strokes.first;
|
||||
GP_Sculpt_Settings *gset = &ts->gp_sculpt;
|
||||
int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0;
|
||||
const char *align_flag = &ts->gpencil_v3d_align;
|
||||
bool is_depth = (bool)(*align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE));
|
||||
const char align_flag = ts->gpencil_v3d_align;
|
||||
bool is_depth = (bool)(align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE));
|
||||
const bool is_camera = (bool)(ts->gp_sculpt.lock_axis == 0) &&
|
||||
(tgpi->rv3d->persp == RV3D_CAMOB) && (!is_depth);
|
||||
|
||||
|
@ -1081,8 +1081,8 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
|
|||
gpencil_apply_parent_point(tgpi->depsgraph, tgpi->ob, tgpi->gpl, pt);
|
||||
}
|
||||
|
||||
/* if camera view, reproject flat to view to avoid perspective effect */
|
||||
if (is_camera) {
|
||||
/* If camera view or view projection, reproject flat to view to avoid perspective effect. */
|
||||
if ((align_flag & GP_PROJECT_VIEWSPACE) || is_camera) {
|
||||
ED_gpencil_project_stroke_to_view(C, tgpi->gpl, gps);
|
||||
}
|
||||
|
||||
|
|
|
@ -99,6 +99,30 @@ void ED_space_clip_set_clip(struct bContext *C,
|
|||
struct Mask *ED_space_clip_get_mask(struct SpaceClip *sc);
|
||||
void ED_space_clip_set_mask(struct bContext *C, struct SpaceClip *sc, struct Mask *mask);
|
||||
|
||||
/* Locked state is used to preserve current clip editor viewport upon changes. Example usage:
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* ClipViewLockState lock_state;
|
||||
* ED_clip_view_lock_state_store(C, &lock_state);
|
||||
*
|
||||
* <change selection>
|
||||
*
|
||||
* ED_clip_view_lock_state_restore_no_jump(C, &lock_state);
|
||||
*
|
||||
* These function are to be used from space clip editor context only. Otherwise debug builds will
|
||||
* assert, release builds will crash. */
|
||||
|
||||
typedef struct ClipViewLockState {
|
||||
float offset_x, offset_y;
|
||||
float lock_offset_x, lock_offset_y;
|
||||
float zoom;
|
||||
} ClipViewLockState;
|
||||
|
||||
void ED_clip_view_lock_state_store(const struct bContext *C, ClipViewLockState *state);
|
||||
void ED_clip_view_lock_state_restore_no_jump(const struct bContext *C,
|
||||
const ClipViewLockState *state);
|
||||
|
||||
/* ** clip_ops.c ** */
|
||||
void ED_operatormacros_clip(void);
|
||||
|
||||
|
|
|
@ -63,7 +63,10 @@ void ED_mask_point_pos__reverse(
|
|||
struct ScrArea *area, struct ARegion *region, float x, float y, float *xr, float *yr);
|
||||
|
||||
void ED_mask_cursor_location_get(struct ScrArea *area, float cursor[2]);
|
||||
bool ED_mask_selected_minmax(const struct bContext *C, float min[2], float max[2]);
|
||||
bool ED_mask_selected_minmax(const struct bContext *C,
|
||||
float min[2],
|
||||
float max[2],
|
||||
bool include_handles);
|
||||
|
||||
/* mask_draw.c */
|
||||
void ED_mask_draw(const struct bContext *C, const char draw_flag, const char draw_type);
|
||||
|
|
|
@ -991,12 +991,26 @@ extern void ui_draw_but(const struct bContext *C,
|
|||
uiBut *but,
|
||||
rcti *rect);
|
||||
|
||||
/**
|
||||
* Info about what the separator character separates, used to decide between different drawing
|
||||
* styles. E.g. we never want a shortcut string to be clipped, but other hint strings can be
|
||||
* clipped.
|
||||
*/
|
||||
typedef enum {
|
||||
UI_MENU_ITEM_SEPARATOR_NONE,
|
||||
/** Separator is used to indicate shortcut string of this item. Shortcut string will not get
|
||||
* clipped. */
|
||||
UI_MENU_ITEM_SEPARATOR_SHORTCUT,
|
||||
/** Separator is used to indicate some additional hint to display for this item. Hint string will
|
||||
* get clipped before the normal text. */
|
||||
UI_MENU_ITEM_SEPARATOR_HINT,
|
||||
} uiMenuItemSeparatorType;
|
||||
void ui_draw_menu_item(const struct uiFontStyle *fstyle,
|
||||
rcti *rect,
|
||||
const char *name,
|
||||
int iconid,
|
||||
int state,
|
||||
bool use_sep,
|
||||
uiMenuItemSeparatorType separator_type,
|
||||
int *r_xmax);
|
||||
void ui_draw_preview_item(
|
||||
const struct uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state);
|
||||
|
|
|
@ -610,7 +610,15 @@ static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region)
|
|||
char *name = data->items.names[a];
|
||||
int icon = data->items.icons[a];
|
||||
char *name_sep_test = NULL;
|
||||
const bool use_sep_char = data->use_sep || (state & UI_BUT_HAS_SEP_CHAR);
|
||||
|
||||
uiMenuItemSeparatorType separator_type = UI_MENU_ITEM_SEPARATOR_NONE;
|
||||
if (data->use_sep) {
|
||||
separator_type = UI_MENU_ITEM_SEPARATOR_SHORTCUT;
|
||||
}
|
||||
/* Only set for displaying additional hint (e.g. library name of a linked data-block). */
|
||||
else if (state & UI_BUT_HAS_SEP_CHAR) {
|
||||
separator_type = UI_MENU_ITEM_SEPARATOR_HINT;
|
||||
}
|
||||
|
||||
ui_searchbox_butrect(&rect, data, a);
|
||||
|
||||
|
@ -623,7 +631,7 @@ static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region)
|
|||
}
|
||||
|
||||
/* Simple menu item. */
|
||||
ui_draw_menu_item(&data->fstyle, &rect, name, icon, state, use_sep_char, NULL);
|
||||
ui_draw_menu_item(&data->fstyle, &rect, name, icon, state, separator_type, NULL);
|
||||
}
|
||||
else {
|
||||
/* Split menu item, faded text before the separator. */
|
||||
|
@ -637,8 +645,13 @@ static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region)
|
|||
const char name_sep_prev = *name_sep;
|
||||
*name_sep = '\0';
|
||||
int name_width = 0;
|
||||
ui_draw_menu_item(
|
||||
&data->fstyle, &rect, name, 0, state | UI_BUT_INACTIVE, false, &name_width);
|
||||
ui_draw_menu_item(&data->fstyle,
|
||||
&rect,
|
||||
name,
|
||||
0,
|
||||
state | UI_BUT_INACTIVE,
|
||||
UI_MENU_ITEM_SEPARATOR_NONE,
|
||||
&name_width);
|
||||
*name_sep = name_sep_prev;
|
||||
rect.xmin += name_width;
|
||||
rect.xmin += UI_UNIT_X / 4;
|
||||
|
@ -650,7 +663,7 @@ static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region)
|
|||
|
||||
/* The previous menu item draws the active selection. */
|
||||
ui_draw_menu_item(
|
||||
&data->fstyle, &rect, name_sep, icon, state & ~UI_ACTIVE, use_sep_char, NULL);
|
||||
&data->fstyle, &rect, name_sep, icon, state & ~UI_ACTIVE, separator_type, NULL);
|
||||
}
|
||||
}
|
||||
/* indicate more */
|
||||
|
@ -943,10 +956,16 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe
|
|||
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, text_pre),
|
||||
data->items.icons[a],
|
||||
state,
|
||||
false,
|
||||
UI_MENU_ITEM_SEPARATOR_NONE,
|
||||
NULL);
|
||||
ui_draw_menu_item(&data->fstyle,
|
||||
&rect_post,
|
||||
data->items.names[a],
|
||||
0,
|
||||
state,
|
||||
data->use_sep ? UI_MENU_ITEM_SEPARATOR_SHORTCUT :
|
||||
UI_MENU_ITEM_SEPARATOR_NONE,
|
||||
NULL);
|
||||
ui_draw_menu_item(
|
||||
&data->fstyle, &rect_post, data->items.names[a], 0, state, data->use_sep, NULL);
|
||||
}
|
||||
}
|
||||
/* indicate more */
|
||||
|
|
|
@ -1533,27 +1533,24 @@ static void ui_text_clip_right_ex(const uiFontStyle *fstyle,
|
|||
{
|
||||
BLI_assert(str[0]);
|
||||
|
||||
/* If the trailing ellipsis takes more than 20% of all available width, just cut the string
|
||||
* (as using the ellipsis would remove even more useful chars, and we cannot show much
|
||||
* already!).
|
||||
*/
|
||||
if (sep_strwidth / okwidth > 0.2f) {
|
||||
float tmp;
|
||||
const int l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth, &tmp);
|
||||
str[l_end] = '\0';
|
||||
if (r_final_len) {
|
||||
*r_final_len = (size_t)l_end;
|
||||
}
|
||||
}
|
||||
else {
|
||||
float tmp;
|
||||
const int l_end = BLF_width_to_strlen(
|
||||
fstyle->uifont_id, str, max_len, okwidth - sep_strwidth, &tmp);
|
||||
/* How many BYTES (not characters) of this utf-8 string can fit, along with appended ellipsis. */
|
||||
int l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth - sep_strwidth, NULL);
|
||||
|
||||
if (l_end > 0) {
|
||||
/* At least one character, so clip and add the ellipsis. */
|
||||
memcpy(str + l_end, sep, sep_len + 1); /* +1 for trailing '\0'. */
|
||||
if (r_final_len) {
|
||||
*r_final_len = (size_t)(l_end) + sep_len;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Otherwise fit as much as we can without adding an ellipsis. */
|
||||
l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth, NULL);
|
||||
str[l_end] = '\0';
|
||||
if (r_final_len) {
|
||||
*r_final_len = (size_t)l_end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5211,8 +5208,7 @@ void ui_draw_tooltip_background(const uiStyle *UNUSED(style), uiBlock *UNUSED(bl
|
|||
*
|
||||
* \param state: The state of the button,
|
||||
* typically #UI_ACTIVE, #UI_BUT_DISABLED, #UI_BUT_INACTIVE.
|
||||
* \param use_sep: When true, characters after the last #UI_SEP_CHAR are right aligned,
|
||||
* use for displaying key shortcuts.
|
||||
* \param separator_type: The kind of separator which controls if and how the string is clipped.
|
||||
* \param r_xmax: The right hand position of the text, this takes into the icon,
|
||||
* padding and text clipping when there is not enough room to display the full text.
|
||||
*/
|
||||
|
@ -5221,11 +5217,13 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
|
|||
const char *name,
|
||||
int iconid,
|
||||
int state,
|
||||
bool use_sep,
|
||||
uiMenuItemSeparatorType separator_type,
|
||||
int *r_xmax)
|
||||
{
|
||||
uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM);
|
||||
const rcti _rect = *rect;
|
||||
int max_hint_width = INT_MAX;
|
||||
int padding = 0.25f * UI_UNIT_X;
|
||||
char *cpoin = NULL;
|
||||
|
||||
wt->state(wt, state, 0, UI_EMBOSS_UNDEFINED);
|
||||
|
@ -5234,13 +5232,13 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
|
|||
UI_fontstyle_set(fstyle);
|
||||
|
||||
/* text location offset */
|
||||
rect->xmin += 0.25f * UI_UNIT_X;
|
||||
rect->xmin += padding;
|
||||
if (iconid) {
|
||||
rect->xmin += UI_DPI_ICON_SIZE;
|
||||
}
|
||||
|
||||
/* cut string in 2 parts? */
|
||||
if (use_sep) {
|
||||
if (separator_type != UI_MENU_ITEM_SEPARATOR_NONE) {
|
||||
cpoin = strrchr(name, UI_SEP_CHAR);
|
||||
if (cpoin) {
|
||||
*cpoin = 0;
|
||||
|
@ -5253,7 +5251,30 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
|
|||
BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
|
||||
}
|
||||
|
||||
rect->xmax -= BLF_width(fstyle->uifont_id, cpoin + 1, INT_MAX) + UI_DPI_ICON_SIZE;
|
||||
if (separator_type == UI_MENU_ITEM_SEPARATOR_SHORTCUT) {
|
||||
/* Shrink rect to exclude the shortcut string. */
|
||||
rect->xmax -= BLF_width(fstyle->uifont_id, cpoin + 1, INT_MAX) + UI_DPI_ICON_SIZE;
|
||||
}
|
||||
else if (separator_type == UI_MENU_ITEM_SEPARATOR_HINT) {
|
||||
/* Determine max-width for the hint string to leave the name string un-clipped (if there's
|
||||
* enough space to display it). */
|
||||
|
||||
const int available_width = BLI_rcti_size_x(rect) - padding;
|
||||
const int name_width = BLF_width(fstyle->uifont_id, name, INT_MAX);
|
||||
const int hint_width = BLF_width(fstyle->uifont_id, cpoin + 1, INT_MAX) + padding;
|
||||
|
||||
if ((name_width + hint_width) > available_width) {
|
||||
/* Clipping width for hint string. */
|
||||
max_hint_width = available_width * 0.40f;
|
||||
/* Clipping xmax for clipping of item name. */
|
||||
rect->xmax = (hint_width < max_hint_width) ?
|
||||
(rect->xmax - hint_width) :
|
||||
(rect->xmin + (available_width - max_hint_width));
|
||||
}
|
||||
}
|
||||
else {
|
||||
BLI_assert(!"Unknwon menu item separator type");
|
||||
}
|
||||
|
||||
if (fstyle->kerning == 1) {
|
||||
BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
|
||||
|
@ -5308,15 +5329,26 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
|
|||
}
|
||||
|
||||
/* part text right aligned */
|
||||
if (use_sep) {
|
||||
if (separator_type != UI_MENU_ITEM_SEPARATOR_NONE) {
|
||||
if (cpoin) {
|
||||
/* Set inactive state for grayed out text. */
|
||||
wt->state(wt, state | UI_BUT_INACTIVE, 0, UI_EMBOSS_UNDEFINED);
|
||||
|
||||
char hint_drawstr[UI_MAX_DRAW_STR];
|
||||
{
|
||||
const size_t max_len = sizeof(hint_drawstr);
|
||||
const float minwidth = (float)(UI_DPI_ICON_SIZE);
|
||||
|
||||
BLI_strncpy(hint_drawstr, cpoin + 1, sizeof(hint_drawstr));
|
||||
if (hint_drawstr[0] && (max_hint_width < INT_MAX)) {
|
||||
UI_text_clip_middle_ex(fstyle, hint_drawstr, max_hint_width, minwidth, max_len, '\0');
|
||||
}
|
||||
}
|
||||
|
||||
rect->xmax = _rect.xmax - 5;
|
||||
UI_fontstyle_draw(fstyle,
|
||||
rect,
|
||||
cpoin + 1,
|
||||
hint_drawstr,
|
||||
wt->wcol.text,
|
||||
&(struct uiFontStyleDraw_Params){
|
||||
.align = UI_STYLE_TEXT_RIGHT,
|
||||
|
|
|
@ -507,6 +507,9 @@ static int add_vertex_handle_cyclic(
|
|||
|
||||
static int add_vertex_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
MaskViewLockState lock_state;
|
||||
ED_mask_view_lock_state_store(C, &lock_state);
|
||||
|
||||
Mask *mask = CTX_data_edit_mask(C);
|
||||
if (mask == NULL) {
|
||||
/* if there's no active mask, create one */
|
||||
|
@ -548,6 +551,8 @@ static int add_vertex_exec(bContext *C, wmOperator *op)
|
|||
|
||||
DEG_id_tag_update(&mask->id, ID_RECALC_GEOMETRY);
|
||||
|
||||
ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
|
@ -690,6 +695,9 @@ void MASK_OT_add_feather_vertex(wmOperatorType *ot)
|
|||
static int create_primitive_from_points(
|
||||
bContext *C, wmOperator *op, const float (*points)[2], int num_points, char handle_type)
|
||||
{
|
||||
MaskViewLockState lock_state;
|
||||
ED_mask_view_lock_state_store(C, &lock_state);
|
||||
|
||||
ScrArea *area = CTX_wm_area(C);
|
||||
int size = RNA_float_get(op->ptr, "size");
|
||||
|
||||
|
@ -752,6 +760,8 @@ static int create_primitive_from_points(
|
|||
|
||||
DEG_id_tag_update(&mask->id, ID_RECALC_GEOMETRY);
|
||||
|
||||
ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
|
|
|
@ -184,3 +184,39 @@ void ED_operatormacros_mask(void)
|
|||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Lock-to-selection viewport preservation
|
||||
* \{ */
|
||||
|
||||
void ED_mask_view_lock_state_store(const bContext *C, MaskViewLockState *state)
|
||||
{
|
||||
SpaceClip *space_clip = CTX_wm_space_clip(C);
|
||||
if (space_clip != NULL) {
|
||||
ED_clip_view_lock_state_store(C, &state->space_clip_state);
|
||||
}
|
||||
}
|
||||
|
||||
void ED_mask_view_lock_state_restore_no_jump(const bContext *C, const MaskViewLockState *state)
|
||||
{
|
||||
SpaceClip *space_clip = CTX_wm_space_clip(C);
|
||||
if (space_clip != NULL) {
|
||||
if ((space_clip->flag & SC_LOCK_SELECTION) == 0) {
|
||||
/* Early output if the editor is not locked to selection.
|
||||
* Avoids forced dependency graph evaluation here. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Mask's lock-to-selection requres deformed splines to be evaluated to calculate bounds of
|
||||
* points after animation has been evaluated. The restore-no-jump type of function does
|
||||
* calculation of new offset for the view for an updated state of mask to cancel the offset out
|
||||
* by modifying locked offset. In order to do such calculation mask needs to be evaluated after
|
||||
* modification by an operator. */
|
||||
struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
(void)depsgraph;
|
||||
|
||||
ED_clip_view_lock_state_restore_no_jump(C, &state->space_clip_state);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "ED_clip.h"
|
||||
|
||||
struct Mask;
|
||||
struct bContext;
|
||||
struct wmOperatorType;
|
||||
|
@ -92,6 +94,19 @@ void ED_mask_select_flush_all(struct Mask *mask);
|
|||
bool ED_maskedit_poll(struct bContext *C);
|
||||
bool ED_maskedit_mask_poll(struct bContext *C);
|
||||
|
||||
/* Generalized solution for preserving editor viewport when making changes while lock-to-selection
|
||||
* is enabled.
|
||||
* Any mask operator can use this API, without worrying that some editors do not have an idea of
|
||||
* lock-to-selection. */
|
||||
|
||||
typedef struct MaskViewLockState {
|
||||
ClipViewLockState space_clip_state;
|
||||
} MaskViewLockState;
|
||||
|
||||
void ED_mask_view_lock_state_store(const struct bContext *C, MaskViewLockState *state);
|
||||
void ED_mask_view_lock_state_restore_no_jump(const struct bContext *C,
|
||||
const MaskViewLockState *state);
|
||||
|
||||
/* mask_query.c */
|
||||
bool ED_mask_find_nearest_diff_point(const struct bContext *C,
|
||||
struct Mask *mask,
|
||||
|
|
|
@ -226,6 +226,12 @@ typedef struct SlidePointData {
|
|||
int width, height;
|
||||
|
||||
float prev_mouse_coord[2];
|
||||
|
||||
/* Previous clip coordinate which was resolved from mouse position (0, 0).
|
||||
* Is used to compansate for view offste moving in-between of mouse events when
|
||||
* lock-to-selection is enabled. */
|
||||
float prev_zero_coord[2];
|
||||
|
||||
float no[2];
|
||||
|
||||
bool is_curvature_only, is_accurate, is_initial_feather, is_overall_feather;
|
||||
|
@ -431,6 +437,9 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
|
|||
const float threshold = 19;
|
||||
eMaskWhichHandle which_handle;
|
||||
|
||||
MaskViewLockState lock_state;
|
||||
ED_mask_view_lock_state_store(C, &lock_state);
|
||||
|
||||
ED_mask_mouse_pos(area, region, event->mval, co);
|
||||
ED_mask_get_size(area, &width, &height);
|
||||
|
||||
|
@ -530,7 +539,15 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
|
|||
}
|
||||
customdata->which_handle = which_handle;
|
||||
|
||||
{
|
||||
WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
|
||||
DEG_id_tag_update(&mask->id, 0);
|
||||
|
||||
ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
|
||||
}
|
||||
|
||||
ED_mask_mouse_pos(area, region, event->mval, customdata->prev_mouse_coord);
|
||||
ED_mask_mouse_pos(area, region, (int[2]){0, 0}, customdata->prev_zero_coord);
|
||||
}
|
||||
|
||||
return customdata;
|
||||
|
@ -655,10 +672,24 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
|||
|
||||
ED_mask_mouse_pos(area, region, event->mval, co);
|
||||
sub_v2_v2v2(delta, co, data->prev_mouse_coord);
|
||||
copy_v2_v2(data->prev_mouse_coord, co);
|
||||
|
||||
/* Compensate for possibly moved view offset since the last event.
|
||||
* The idea is to see how mapping of a fixed and known position did change. */
|
||||
{
|
||||
float zero_coord[2];
|
||||
ED_mask_mouse_pos(area, region, (int[2]){0, 0}, zero_coord);
|
||||
|
||||
float zero_delta[2];
|
||||
sub_v2_v2v2(zero_delta, zero_coord, data->prev_zero_coord);
|
||||
sub_v2_v2(delta, zero_delta);
|
||||
|
||||
copy_v2_v2(data->prev_zero_coord, zero_coord);
|
||||
}
|
||||
|
||||
if (data->is_accurate) {
|
||||
mul_v2_fl(delta, 0.2f);
|
||||
}
|
||||
copy_v2_v2(data->prev_mouse_coord, co);
|
||||
|
||||
if (data->action == SLIDE_ACTION_HANDLE) {
|
||||
float new_handle[2];
|
||||
|
@ -966,6 +997,9 @@ static SlideSplineCurvatureData *slide_spline_curvature_customdata(bContext *C,
|
|||
float u, co[2];
|
||||
BezTriple *next_bezt;
|
||||
|
||||
MaskViewLockState lock_state;
|
||||
ED_mask_view_lock_state_store(C, &lock_state);
|
||||
|
||||
ED_mask_mouse_pos(CTX_wm_area(C), CTX_wm_region(C), event->mval, co);
|
||||
|
||||
if (!ED_mask_find_nearest_diff_point(C,
|
||||
|
@ -1047,6 +1081,9 @@ static SlideSplineCurvatureData *slide_spline_curvature_customdata(bContext *C,
|
|||
mask_layer->act_point = point;
|
||||
ED_mask_select_flush_all(mask);
|
||||
|
||||
DEG_id_tag_update(&mask->id, 0);
|
||||
ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
|
||||
|
||||
return slide_data;
|
||||
}
|
||||
|
||||
|
|
|
@ -604,7 +604,7 @@ void ED_mask_point_pos__reverse(
|
|||
*yr = co[1];
|
||||
}
|
||||
|
||||
bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2])
|
||||
bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2], bool include_handles)
|
||||
{
|
||||
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
||||
Mask *mask = CTX_data_edit_mask(C);
|
||||
|
@ -638,22 +638,29 @@ bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2])
|
|||
}
|
||||
if (bezt->f2 & SELECT) {
|
||||
minmax_v2v2_v2(min, max, deform_point->bezt.vec[1]);
|
||||
ok = true;
|
||||
}
|
||||
if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
|
||||
|
||||
if (!include_handles) {
|
||||
/* Ignore handles. */
|
||||
}
|
||||
else if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
|
||||
BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_STICK, handle);
|
||||
minmax_v2v2_v2(min, max, handle);
|
||||
ok = true;
|
||||
}
|
||||
else {
|
||||
if ((bezt->f1 & SELECT) && (bezt->h1 != HD_VECT)) {
|
||||
BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_LEFT, handle);
|
||||
minmax_v2v2_v2(min, max, handle);
|
||||
ok = true;
|
||||
}
|
||||
if ((bezt->f3 & SELECT) && (bezt->h2 != HD_VECT)) {
|
||||
BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_RIGHT, handle);
|
||||
minmax_v2v2_v2(min, max, handle);
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -214,12 +214,17 @@ static int select_all_exec(bContext *C, wmOperator *op)
|
|||
Mask *mask = CTX_data_edit_mask(C);
|
||||
int action = RNA_enum_get(op->ptr, "action");
|
||||
|
||||
MaskViewLockState lock_state;
|
||||
ED_mask_view_lock_state_store(C, &lock_state);
|
||||
|
||||
ED_mask_select_toggle_all(mask, action);
|
||||
ED_mask_select_flush_all(mask);
|
||||
|
||||
DEG_id_tag_update(&mask->id, ID_RECALC_SELECT);
|
||||
WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
|
||||
|
||||
ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
|
@ -261,6 +266,9 @@ static int select_exec(bContext *C, wmOperator *op)
|
|||
eMaskWhichHandle which_handle;
|
||||
const float threshold = 19;
|
||||
|
||||
MaskViewLockState lock_state;
|
||||
ED_mask_view_lock_state_store(C, &lock_state);
|
||||
|
||||
RNA_float_get_array(op->ptr, "location", co);
|
||||
|
||||
point = ED_mask_point_find_nearest(
|
||||
|
@ -324,6 +332,8 @@ static int select_exec(bContext *C, wmOperator *op)
|
|||
DEG_id_tag_update(&mask->id, ID_RECALC_SELECT);
|
||||
WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
|
||||
|
||||
ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
|
@ -364,12 +374,15 @@ static int select_exec(bContext *C, wmOperator *op)
|
|||
DEG_id_tag_update(&mask->id, ID_RECALC_SELECT);
|
||||
WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
|
||||
|
||||
ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
if (deselect_all) {
|
||||
/* For clip editor tracks, leave deselect all to clip editor. */
|
||||
if (!ED_clip_can_select(C)) {
|
||||
ED_mask_deselect_all(C);
|
||||
ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7736,7 +7736,8 @@ static bool sculpt_needs_connectivity_info(const Sculpt *sd,
|
|||
(brush->sculpt_tool == SCULPT_TOOL_FAIRING) ||
|
||||
(brush->sculpt_tool == SCULPT_TOOL_SLIDE_RELAX) ||
|
||||
(brush->sculpt_tool == SCULPT_TOOL_CLOTH) || (brush->sculpt_tool == SCULPT_TOOL_SMEAR) ||
|
||||
(brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS));
|
||||
(brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS) ||
|
||||
(brush->sculpt_tool == SCULPT_TOOL_DISPLACEMENT_SMEAR));
|
||||
}
|
||||
|
||||
void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush)
|
||||
|
|
|
@ -327,118 +327,18 @@ void ED_clip_update_frame(const Main *mainp, int cfra)
|
|||
}
|
||||
}
|
||||
|
||||
static bool selected_tracking_boundbox(SpaceClip *sc, float min[2], float max[2])
|
||||
bool ED_clip_view_selection(const bContext *C, ARegion *UNUSED(region), bool fit)
|
||||
{
|
||||
MovieClip *clip = ED_space_clip_get_clip(sc);
|
||||
MovieTrackingTrack *track;
|
||||
int width, height;
|
||||
bool ok = false;
|
||||
ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
|
||||
int framenr = ED_space_clip_get_clip_frame_number(sc);
|
||||
|
||||
INIT_MINMAX2(min, max);
|
||||
|
||||
ED_space_clip_get_size(sc, &width, &height);
|
||||
|
||||
track = tracksbase->first;
|
||||
while (track) {
|
||||
if (TRACK_VIEW_SELECTED(sc, track)) {
|
||||
MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
|
||||
|
||||
if (marker) {
|
||||
float pos[3];
|
||||
|
||||
pos[0] = marker->pos[0] + track->offset[0];
|
||||
pos[1] = marker->pos[1] + track->offset[1];
|
||||
pos[2] = 0.0f;
|
||||
|
||||
/* undistortion happens for normalized coords */
|
||||
if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
|
||||
/* undistortion happens for normalized coords */
|
||||
ED_clip_point_undistorted_pos(sc, pos, pos);
|
||||
}
|
||||
|
||||
pos[0] *= width;
|
||||
pos[1] *= height;
|
||||
|
||||
mul_v3_m4v3(pos, sc->stabmat, pos);
|
||||
|
||||
minmax_v2v2_v2(min, max, pos);
|
||||
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
track = track->next;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static bool selected_boundbox(const bContext *C, float min[2], float max[2])
|
||||
{
|
||||
SpaceClip *sc = CTX_wm_space_clip(C);
|
||||
if (sc->mode == SC_MODE_TRACKING) {
|
||||
return selected_tracking_boundbox(sc, min, max);
|
||||
}
|
||||
|
||||
if (ED_mask_selected_minmax(C, min, max)) {
|
||||
MovieClip *clip = ED_space_clip_get_clip(sc);
|
||||
int width, height;
|
||||
ED_space_clip_get_size(sc, &width, &height);
|
||||
BKE_mask_coord_to_movieclip(clip, &sc->user, min, min);
|
||||
BKE_mask_coord_to_movieclip(clip, &sc->user, max, max);
|
||||
min[0] *= width;
|
||||
min[1] *= height;
|
||||
max[0] *= width;
|
||||
max[1] *= height;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ED_clip_view_selection(const bContext *C, ARegion *region, bool fit)
|
||||
{
|
||||
SpaceClip *sc = CTX_wm_space_clip(C);
|
||||
int w, h, frame_width, frame_height;
|
||||
float min[2], max[2];
|
||||
|
||||
ED_space_clip_get_size(sc, &frame_width, &frame_height);
|
||||
|
||||
if ((frame_width == 0) || (frame_height == 0) || (sc->clip == NULL)) {
|
||||
float offset_x, offset_y;
|
||||
float zoom;
|
||||
if (!clip_view_calculate_view_selection(C, fit, &offset_x, &offset_y, &zoom)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!selected_boundbox(C, min, max)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* center view */
|
||||
clip_view_center_to_point(
|
||||
sc, (max[0] + min[0]) / (2 * frame_width), (max[1] + min[1]) / (2 * frame_height));
|
||||
|
||||
w = max[0] - min[0];
|
||||
h = max[1] - min[1];
|
||||
|
||||
/* set zoom to see all selection */
|
||||
if (w > 0 && h > 0) {
|
||||
int width, height;
|
||||
float zoomx, zoomy, newzoom, aspx, aspy;
|
||||
|
||||
ED_space_clip_get_aspect(sc, &aspx, &aspy);
|
||||
|
||||
width = BLI_rcti_size_x(®ion->winrct) + 1;
|
||||
height = BLI_rcti_size_y(®ion->winrct) + 1;
|
||||
|
||||
zoomx = (float)width / w / aspx;
|
||||
zoomy = (float)height / h / aspy;
|
||||
|
||||
newzoom = 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy));
|
||||
|
||||
if (fit || sc->zoom > newzoom) {
|
||||
sc->zoom = newzoom;
|
||||
}
|
||||
}
|
||||
SpaceClip *sc = CTX_wm_space_clip(C);
|
||||
sc->xof = offset_x;
|
||||
sc->yof = offset_y;
|
||||
sc->zoom = zoom;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1177,3 +1077,47 @@ void clip_start_prefetch_job(const bContext *C)
|
|||
/* and finally start the job */
|
||||
WM_jobs_start(CTX_wm_manager(C), wm_job);
|
||||
}
|
||||
|
||||
void ED_clip_view_lock_state_store(const bContext *C, ClipViewLockState *state)
|
||||
{
|
||||
SpaceClip *space_clip = CTX_wm_space_clip(C);
|
||||
BLI_assert(space_clip != NULL);
|
||||
|
||||
state->offset_x = space_clip->xof;
|
||||
state->offset_y = space_clip->yof;
|
||||
state->zoom = space_clip->zoom;
|
||||
|
||||
state->lock_offset_x = 0.0f;
|
||||
state->lock_offset_y = 0.0f;
|
||||
|
||||
if ((space_clip->flag & SC_LOCK_SELECTION) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!clip_view_calculate_view_selection(
|
||||
C, false, &state->offset_x, &state->offset_y, &state->zoom)) {
|
||||
return;
|
||||
}
|
||||
|
||||
state->lock_offset_x = space_clip->xlockof;
|
||||
state->lock_offset_y = space_clip->ylockof;
|
||||
}
|
||||
|
||||
void ED_clip_view_lock_state_restore_no_jump(const bContext *C, const ClipViewLockState *state)
|
||||
{
|
||||
SpaceClip *space_clip = CTX_wm_space_clip(C);
|
||||
BLI_assert(space_clip != NULL);
|
||||
|
||||
if ((space_clip->flag & SC_LOCK_SELECTION) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
float offset_x, offset_y;
|
||||
float zoom;
|
||||
if (!clip_view_calculate_view_selection(C, false, &offset_x, &offset_y, &zoom)) {
|
||||
return;
|
||||
}
|
||||
|
||||
space_clip->xlockof = state->offset_x + state->lock_offset_x - offset_x;
|
||||
space_clip->ylockof = state->offset_y + state->lock_offset_y - offset_y;
|
||||
}
|
||||
|
|
|
@ -171,8 +171,13 @@ void clip_delete_plane_track(struct bContext *C,
|
|||
struct MovieClip *clip,
|
||||
struct MovieTrackingPlaneTrack *plane_track);
|
||||
|
||||
void clip_view_offset_for_center_to_point(
|
||||
SpaceClip *sc, const float x, const float y, float *r_offset_x, float *r_offset_y);
|
||||
void clip_view_center_to_point(SpaceClip *sc, float x, float y);
|
||||
|
||||
bool clip_view_calculate_view_selection(
|
||||
const struct bContext *C, bool fit, float *r_offset_x, float *r_offset_y, float *r_zoom);
|
||||
|
||||
void clip_draw_sfra_efra(struct View2D *v2d, struct Scene *scene);
|
||||
|
||||
/* tracking_ops.c */
|
||||
|
|
|
@ -1840,8 +1840,16 @@ void CLIP_OT_cursor_set(wmOperatorType *ot)
|
|||
static int lock_selection_togglee_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
SpaceClip *space_clip = CTX_wm_space_clip(C);
|
||||
|
||||
ClipViewLockState lock_state;
|
||||
ED_clip_view_lock_state_store(C, &lock_state);
|
||||
|
||||
space_clip->flag ^= SC_LOCK_SELECTION;
|
||||
|
||||
ED_clip_view_lock_state_restore_no_jump(C, &lock_state);
|
||||
|
||||
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CLIP, NULL);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,10 +27,12 @@
|
|||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_rect.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_animsys.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_mask.h"
|
||||
#include "BKE_movieclip.h"
|
||||
#include "BKE_tracking.h"
|
||||
|
||||
|
@ -44,6 +46,7 @@
|
|||
#include "WM_types.h"
|
||||
|
||||
#include "ED_clip.h"
|
||||
#include "ED_mask.h"
|
||||
#include "ED_screen.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
|
@ -395,16 +398,152 @@ void clip_delete_plane_track(bContext *C, MovieClip *clip, MovieTrackingPlaneTra
|
|||
DEG_id_tag_update(&clip->id, 0);
|
||||
}
|
||||
|
||||
void clip_view_center_to_point(SpaceClip *sc, float x, float y)
|
||||
/* Calculate space clip offset to be centered at the given point. */
|
||||
void clip_view_offset_for_center_to_point(
|
||||
SpaceClip *sc, const float x, const float y, float *r_offset_x, float *r_offset_y)
|
||||
{
|
||||
int width, height;
|
||||
float aspx, aspy;
|
||||
|
||||
ED_space_clip_get_size(sc, &width, &height);
|
||||
|
||||
float aspx, aspy;
|
||||
ED_space_clip_get_aspect(sc, &aspx, &aspy);
|
||||
|
||||
sc->xof = (x - 0.5f) * width * aspx;
|
||||
sc->yof = (y - 0.5f) * height * aspy;
|
||||
*r_offset_x = (x - 0.5f) * width * aspx;
|
||||
*r_offset_y = (y - 0.5f) * height * aspy;
|
||||
}
|
||||
|
||||
void clip_view_center_to_point(SpaceClip *sc, float x, float y)
|
||||
{
|
||||
clip_view_offset_for_center_to_point(sc, x, y, &sc->xof, &sc->yof);
|
||||
}
|
||||
|
||||
static bool selected_tracking_boundbox(SpaceClip *sc, float min[2], float max[2])
|
||||
{
|
||||
MovieClip *clip = ED_space_clip_get_clip(sc);
|
||||
MovieTrackingTrack *track;
|
||||
int width, height;
|
||||
bool ok = false;
|
||||
ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
|
||||
int framenr = ED_space_clip_get_clip_frame_number(sc);
|
||||
|
||||
INIT_MINMAX2(min, max);
|
||||
|
||||
ED_space_clip_get_size(sc, &width, &height);
|
||||
|
||||
track = tracksbase->first;
|
||||
while (track) {
|
||||
if (TRACK_VIEW_SELECTED(sc, track)) {
|
||||
MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
|
||||
|
||||
if (marker) {
|
||||
float pos[3];
|
||||
|
||||
pos[0] = marker->pos[0] + track->offset[0];
|
||||
pos[1] = marker->pos[1] + track->offset[1];
|
||||
pos[2] = 0.0f;
|
||||
|
||||
/* undistortion happens for normalized coords */
|
||||
if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
|
||||
/* undistortion happens for normalized coords */
|
||||
ED_clip_point_undistorted_pos(sc, pos, pos);
|
||||
}
|
||||
|
||||
pos[0] *= width;
|
||||
pos[1] *= height;
|
||||
|
||||
mul_v3_m4v3(pos, sc->stabmat, pos);
|
||||
|
||||
minmax_v2v2_v2(min, max, pos);
|
||||
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
track = track->next;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static bool selected_boundbox(const bContext *C, float min[2], float max[2], bool include_handles)
|
||||
{
|
||||
SpaceClip *sc = CTX_wm_space_clip(C);
|
||||
if (sc->mode == SC_MODE_TRACKING) {
|
||||
return selected_tracking_boundbox(sc, min, max);
|
||||
}
|
||||
|
||||
if (ED_mask_selected_minmax(C, min, max, include_handles)) {
|
||||
MovieClip *clip = ED_space_clip_get_clip(sc);
|
||||
int width, height;
|
||||
ED_space_clip_get_size(sc, &width, &height);
|
||||
BKE_mask_coord_to_movieclip(clip, &sc->user, min, min);
|
||||
BKE_mask_coord_to_movieclip(clip, &sc->user, max, max);
|
||||
min[0] *= width;
|
||||
min[1] *= height;
|
||||
max[0] *= width;
|
||||
max[1] *= height;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool clip_view_calculate_view_selection(
|
||||
const bContext *C, bool fit, float *r_offset_x, float *r_offset_y, float *r_zoom)
|
||||
{
|
||||
SpaceClip *sc = CTX_wm_space_clip(C);
|
||||
|
||||
int frame_width, frame_height;
|
||||
ED_space_clip_get_size(sc, &frame_width, &frame_height);
|
||||
|
||||
if ((frame_width == 0) || (frame_height == 0) || (sc->clip == NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* NOTE: The `fit` argment is set to truth when doing "View to Selected" operator, and it set to
|
||||
* false when this function is used for Lock-to-Selection functionality. When locking to
|
||||
* selection the handles are to be ignored. So we can deriver the `include_handles` from `fit`.
|
||||
*
|
||||
* TODO(sergey): Make such decision more explicit. Maybe pass usecase for the calculation to tell
|
||||
* operator from lock-to-selection apart. */
|
||||
float min[2], max[2];
|
||||
if (!selected_boundbox(C, min, max, fit)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* center view */
|
||||
clip_view_offset_for_center_to_point(sc,
|
||||
(max[0] + min[0]) / (2 * frame_width),
|
||||
(max[1] + min[1]) / (2 * frame_height),
|
||||
r_offset_x,
|
||||
r_offset_y);
|
||||
|
||||
const int w = max[0] - min[0];
|
||||
const int h = max[1] - min[1];
|
||||
|
||||
/* set zoom to see all selection */
|
||||
*r_zoom = sc->zoom;
|
||||
if (w > 0 && h > 0) {
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
|
||||
int width, height;
|
||||
float zoomx, zoomy, newzoom, aspx, aspy;
|
||||
|
||||
ED_space_clip_get_aspect(sc, &aspx, &aspy);
|
||||
|
||||
width = BLI_rcti_size_x(®ion->winrct) + 1;
|
||||
height = BLI_rcti_size_y(®ion->winrct) + 1;
|
||||
|
||||
zoomx = (float)width / w / aspx;
|
||||
zoomy = (float)height / h / aspy;
|
||||
|
||||
newzoom = 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy));
|
||||
|
||||
if (fit) {
|
||||
*r_zoom = newzoom;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void clip_draw_sfra_efra(View2D *v2d, Scene *scene)
|
||||
|
|
|
@ -994,7 +994,7 @@ static void clip_main_region_draw(const bContext *C, ARegion *region)
|
|||
|
||||
/* callback */
|
||||
/* TODO(sergey): For being consistent with space image the projection needs to be configured
|
||||
* the way how the commented out code does it. This works corrent for tracking data, but it
|
||||
* the way how the commented out code does it. This works correct for tracking data, but it
|
||||
* causes wrong aspect correction for mask editor (see T84990). */
|
||||
// GPU_matrix_push_projection();
|
||||
// wmOrtho2(region->v2d.cur.xmin, region->v2d.cur.xmax, region->v2d.cur.ymin,
|
||||
|
|
|
@ -88,17 +88,16 @@ static int add_marker_exec(bContext *C, wmOperator *op)
|
|||
MovieClip *clip = ED_space_clip_get_clip(sc);
|
||||
float pos[2];
|
||||
|
||||
ClipViewLockState lock_state;
|
||||
ED_clip_view_lock_state_store(C, &lock_state);
|
||||
|
||||
RNA_float_get_array(op->ptr, "location", pos);
|
||||
|
||||
if (!add_marker(C, pos[0], pos[1])) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* Reset offset from locked position, so frame jumping wouldn't be so
|
||||
* confusing.
|
||||
*/
|
||||
sc->xlockof = 0;
|
||||
sc->ylockof = 0;
|
||||
ED_clip_view_lock_state_restore_no_jump(C, &lock_state);
|
||||
|
||||
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
|
||||
|
||||
|
|
|
@ -304,6 +304,9 @@ static int mouse_select(bContext *C, const float co[2], const bool extend, const
|
|||
track = find_nearest_track(sc, tracksbase, co, &distance_to_track);
|
||||
plane_track = find_nearest_plane_track(sc, plane_tracks_base, co, &distance_to_plane_track);
|
||||
|
||||
ClipViewLockState lock_state;
|
||||
ED_clip_view_lock_state_store(C, &lock_state);
|
||||
|
||||
/* Do not select beyond some reasonable distance, that is useless and
|
||||
* prevents the 'deselect on nothing' behavior. */
|
||||
if (distance_to_track > 0.05f) {
|
||||
|
@ -377,10 +380,7 @@ static int mouse_select(bContext *C, const float co[2], const bool extend, const
|
|||
ED_mask_deselect_all(C);
|
||||
}
|
||||
|
||||
if (!extend) {
|
||||
sc->xlockof = 0.0f;
|
||||
sc->ylockof = 0.0f;
|
||||
}
|
||||
ED_clip_view_lock_state_restore_no_jump(C, &lock_state);
|
||||
|
||||
BKE_tracking_dopesheet_tag_update(tracking);
|
||||
|
||||
|
@ -867,15 +867,20 @@ static int select_all_exec(bContext *C, wmOperator *op)
|
|||
MovieClip *clip = ED_space_clip_get_clip(sc);
|
||||
MovieTracking *tracking = &clip->tracking;
|
||||
|
||||
int action = RNA_enum_get(op->ptr, "action");
|
||||
const int action = RNA_enum_get(op->ptr, "action");
|
||||
|
||||
ClipViewLockState lock_state;
|
||||
ED_clip_view_lock_state_store(C, &lock_state);
|
||||
|
||||
bool has_selection = false;
|
||||
|
||||
ED_clip_select_all(sc, action, &has_selection);
|
||||
|
||||
if (!has_selection) {
|
||||
sc->flag &= ~SC_LOCK_SELECTION;
|
||||
}
|
||||
else {
|
||||
ED_clip_view_lock_state_restore_no_jump(C, &lock_state);
|
||||
}
|
||||
|
||||
BKE_tracking_dopesheet_tag_update(tracking);
|
||||
|
||||
|
|
|
@ -794,7 +794,7 @@ static void file_space_subtype_item_extend(bContext *UNUSED(C),
|
|||
}
|
||||
}
|
||||
|
||||
static const char *file_context_dir[] = {"active_file", "active_id", NULL};
|
||||
static const char *file_context_dir[] = {"active_file", "id", NULL};
|
||||
|
||||
static int /*eContextResult*/ file_context(const bContext *C,
|
||||
const char *member,
|
||||
|
|
|
@ -900,7 +900,7 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
|
|||
}
|
||||
}
|
||||
else if (ED_space_image_check_show_maskedit(sima, obedit)) {
|
||||
if (!ED_mask_selected_minmax(C, min, max)) {
|
||||
if (!ED_mask_selected_minmax(C, min, max, true)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3166,13 +3166,80 @@ static void node_geometry_buts_random_attribute(uiLayout *layout,
|
|||
uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE);
|
||||
}
|
||||
|
||||
static bool node_attribute_math_operation_use_input_b(const NodeMathOperation operation)
|
||||
{
|
||||
switch (operation) {
|
||||
case NODE_MATH_ADD:
|
||||
case NODE_MATH_SUBTRACT:
|
||||
case NODE_MATH_MULTIPLY:
|
||||
case NODE_MATH_DIVIDE:
|
||||
case NODE_MATH_POWER:
|
||||
case NODE_MATH_LOGARITHM:
|
||||
case NODE_MATH_MINIMUM:
|
||||
case NODE_MATH_MAXIMUM:
|
||||
case NODE_MATH_LESS_THAN:
|
||||
case NODE_MATH_GREATER_THAN:
|
||||
case NODE_MATH_MODULO:
|
||||
case NODE_MATH_ARCTAN2:
|
||||
case NODE_MATH_SNAP:
|
||||
case NODE_MATH_WRAP:
|
||||
case NODE_MATH_COMPARE:
|
||||
case NODE_MATH_MULTIPLY_ADD:
|
||||
case NODE_MATH_PINGPONG:
|
||||
case NODE_MATH_SMOOTH_MIN:
|
||||
case NODE_MATH_SMOOTH_MAX:
|
||||
return true;
|
||||
case NODE_MATH_SINE:
|
||||
case NODE_MATH_COSINE:
|
||||
case NODE_MATH_TANGENT:
|
||||
case NODE_MATH_ARCSINE:
|
||||
case NODE_MATH_ARCCOSINE:
|
||||
case NODE_MATH_ARCTANGENT:
|
||||
case NODE_MATH_ROUND:
|
||||
case NODE_MATH_ABSOLUTE:
|
||||
case NODE_MATH_FLOOR:
|
||||
case NODE_MATH_CEIL:
|
||||
case NODE_MATH_FRACTION:
|
||||
case NODE_MATH_SQRT:
|
||||
case NODE_MATH_INV_SQRT:
|
||||
case NODE_MATH_SIGN:
|
||||
case NODE_MATH_EXPONENT:
|
||||
case NODE_MATH_RADIANS:
|
||||
case NODE_MATH_DEGREES:
|
||||
case NODE_MATH_SINH:
|
||||
case NODE_MATH_COSH:
|
||||
case NODE_MATH_TANH:
|
||||
case NODE_MATH_TRUNC:
|
||||
return false;
|
||||
}
|
||||
BLI_assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void node_geometry_buts_attribute_math(uiLayout *layout,
|
||||
bContext *UNUSED(C),
|
||||
PointerRNA *ptr)
|
||||
{
|
||||
bNode *node = (bNode *)ptr->data;
|
||||
NodeAttributeMath *node_storage = (NodeAttributeMath *)node->storage;
|
||||
NodeMathOperation operation = (NodeMathOperation)node_storage->operation;
|
||||
|
||||
uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
|
||||
uiItemR(layout, ptr, "input_type_a", DEFAULT_FLAGS, IFACE_("Type A"), ICON_NONE);
|
||||
uiItemR(layout, ptr, "input_type_b", DEFAULT_FLAGS, IFACE_("Type B"), ICON_NONE);
|
||||
|
||||
/* These "use input b / c" checks are copied from the node's code.
|
||||
* They could be de-duplicated if the drawing code was moved to the node's file. */
|
||||
if (node_attribute_math_operation_use_input_b(operation)) {
|
||||
uiItemR(layout, ptr, "input_type_b", DEFAULT_FLAGS, IFACE_("Type B"), ICON_NONE);
|
||||
}
|
||||
if (ELEM(operation,
|
||||
NODE_MATH_MULTIPLY_ADD,
|
||||
NODE_MATH_SMOOTH_MIN,
|
||||
NODE_MATH_SMOOTH_MAX,
|
||||
NODE_MATH_WRAP,
|
||||
NODE_MATH_COMPARE)) {
|
||||
uiItemR(layout, ptr, "input_type_c", DEFAULT_FLAGS, IFACE_("Type C"), ICON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
static void node_geometry_buts_attribute_vector_math(uiLayout *layout,
|
||||
|
@ -3297,6 +3364,16 @@ static void node_geometry_buts_attribute_sample_texture(uiLayout *layout,
|
|||
uiTemplateID(layout, C, ptr, "texture", "texture.new", NULL, NULL, 0, ICON_NONE, NULL);
|
||||
}
|
||||
|
||||
static void node_geometry_buts_points_to_volume(uiLayout *layout,
|
||||
bContext *UNUSED(C),
|
||||
PointerRNA *ptr)
|
||||
{
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
uiLayoutSetPropDecorate(layout, false);
|
||||
uiItemR(layout, ptr, "resolution_mode", DEFAULT_FLAGS, IFACE_("Resolution"), ICON_NONE);
|
||||
uiItemR(layout, ptr, "input_type_radius", DEFAULT_FLAGS, IFACE_("Radius"), ICON_NONE);
|
||||
}
|
||||
|
||||
static void node_geometry_set_butfunc(bNodeType *ntype)
|
||||
{
|
||||
switch (ntype->type) {
|
||||
|
@ -3354,6 +3431,9 @@ static void node_geometry_set_butfunc(bNodeType *ntype)
|
|||
case GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE:
|
||||
ntype->draw_buttons = node_geometry_buts_attribute_sample_texture;
|
||||
break;
|
||||
case GEO_NODE_POINTS_TO_VOLUME:
|
||||
ntype->draw_buttons = node_geometry_buts_points_to_volume;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1395,6 +1395,10 @@ static int sequencer_split_exec(bContext *C, wmOperator *op)
|
|||
|
||||
SEQ_prefetch_stop(scene);
|
||||
|
||||
LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) {
|
||||
seq->tmp = NULL;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH_BACKWARD (Sequence *, seq, ed->seqbasep) {
|
||||
if (use_cursor_position && seq->machine != split_channel) {
|
||||
continue;
|
||||
|
|
|
@ -168,13 +168,13 @@ static void seq_proxy_build_job(const bContext *C, ReportList *reports)
|
|||
}
|
||||
SEQ_CURRENT_END;
|
||||
|
||||
BLI_gset_free(file_list, MEM_freeN);
|
||||
|
||||
if (!selected) {
|
||||
BKE_reportf(reports, RPT_WARNING, "Select movie or image strips");
|
||||
return;
|
||||
}
|
||||
|
||||
BLI_gset_free(file_list, MEM_freeN);
|
||||
|
||||
if (selected && !WM_jobs_is_running(wm_job)) {
|
||||
G.is_break = false;
|
||||
WM_jobs_start(CTX_wm_manager(C), wm_job);
|
||||
|
|
|
@ -224,13 +224,11 @@ void view3d_region_operator_needs_opengl(wmWindow *UNUSED(win), ARegion *region)
|
|||
*/
|
||||
void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist)
|
||||
{
|
||||
float viewdist;
|
||||
|
||||
if (rv3d->rflag & RV3D_ZOFFSET_DISABLED) {
|
||||
return;
|
||||
}
|
||||
|
||||
viewdist = rv3d->dist;
|
||||
float viewdist = rv3d->dist;
|
||||
|
||||
/* special exception for ortho camera (viewdist isnt used for perspective cameras) */
|
||||
if (dist != 0.0f) {
|
||||
|
@ -248,7 +246,6 @@ bool ED_view3d_context_activate(bContext *C)
|
|||
{
|
||||
bScreen *screen = CTX_wm_screen(C);
|
||||
ScrArea *area = CTX_wm_area(C);
|
||||
ARegion *region;
|
||||
|
||||
/* area can be NULL when called from python */
|
||||
if (area == NULL || area->spacetype != SPACE_VIEW3D) {
|
||||
|
@ -259,7 +256,7 @@ bool ED_view3d_context_activate(bContext *C)
|
|||
return false;
|
||||
}
|
||||
|
||||
region = BKE_area_find_region_active_win(area);
|
||||
ARegion *region = BKE_area_find_region_active_win(area);
|
||||
if (region == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
@ -282,9 +279,7 @@ void ED_view3d_clipping_calc_from_boundbox(float clip[4][4],
|
|||
const BoundBox *bb,
|
||||
const bool is_flip)
|
||||
{
|
||||
int val;
|
||||
|
||||
for (val = 0; val < 4; val++) {
|
||||
for (int val = 0; val < 4; val++) {
|
||||
normal_tri_v3(clip[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]);
|
||||
if (UNLIKELY(is_flip)) {
|
||||
negate_v3(clip[val]);
|
||||
|
@ -752,14 +747,12 @@ bool ED_view3d_camera_lock_autokey(View3D *v3d,
|
|||
|
||||
static void view3d_boxview_clip(ScrArea *area)
|
||||
{
|
||||
ARegion *region;
|
||||
BoundBox *bb = MEM_callocN(sizeof(BoundBox), "clipbb");
|
||||
float clip[6][4];
|
||||
float x1 = 0.0f, y1 = 0.0f, z1 = 0.0f, ofs[3] = {0.0f, 0.0f, 0.0f};
|
||||
int val;
|
||||
|
||||
/* create bounding box */
|
||||
for (region = area->regionbase.first; region; region = region->next) {
|
||||
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
|
||||
if (region->regiontype == RGN_TYPE_WINDOW) {
|
||||
RegionView3D *rv3d = region->regiondata;
|
||||
|
||||
|
@ -794,7 +787,7 @@ static void view3d_boxview_clip(ScrArea *area)
|
|||
}
|
||||
}
|
||||
|
||||
for (val = 0; val < 8; val++) {
|
||||
for (int val = 0; val < 8; val++) {
|
||||
if (ELEM(val, 0, 3, 4, 7)) {
|
||||
bb->vec[val][0] = -x1 - ofs[0];
|
||||
}
|
||||
|
@ -826,12 +819,12 @@ static void view3d_boxview_clip(ScrArea *area)
|
|||
normal_tri_v3(clip[5], bb->vec[0], bb->vec[2], bb->vec[1]);
|
||||
|
||||
/* then plane equations */
|
||||
for (val = 0; val < 6; val++) {
|
||||
for (int val = 0; val < 6; val++) {
|
||||
clip[val][3] = -dot_v3v3(clip[val], bb->vec[val % 5]);
|
||||
}
|
||||
|
||||
/* create bounding box */
|
||||
for (region = area->regionbase.first; region; region = region->next) {
|
||||
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
|
||||
if (region->regiontype == RGN_TYPE_WINDOW) {
|
||||
RegionView3D *rv3d = region->regiondata;
|
||||
|
||||
|
@ -950,11 +943,10 @@ void ED_view3d_quadview_update(ScrArea *area, ARegion *region, bool do_clip)
|
|||
{
|
||||
ARegion *region_sync = NULL;
|
||||
RegionView3D *rv3d = region->regiondata;
|
||||
short viewlock;
|
||||
/* this function copies flags from the first of the 3 other quadview
|
||||
* regions to the 2 other, so it assumes this is the region whose
|
||||
* properties are always being edited, weak */
|
||||
viewlock = rv3d->viewlock;
|
||||
short viewlock = rv3d->viewlock;
|
||||
|
||||
if ((viewlock & RV3D_LOCK_ROTATION) == 0) {
|
||||
do_clip = (viewlock & RV3D_BOXCLIP) != 0;
|
||||
|
@ -1015,10 +1007,7 @@ void ED_view3d_quadview_update(ScrArea *area, ARegion *region, bool do_clip)
|
|||
|
||||
static float view_autodist_depth_margin(ARegion *region, const int mval[2], int margin)
|
||||
{
|
||||
ViewDepths depth_temp = {0};
|
||||
rcti rect;
|
||||
float depth_close;
|
||||
|
||||
if (margin == 0) {
|
||||
/* Get Z Depths, needed for perspective, nice for ortho */
|
||||
rect.xmin = mval[0];
|
||||
|
@ -1030,8 +1019,9 @@ static float view_autodist_depth_margin(ARegion *region, const int mval[2], int
|
|||
BLI_rcti_init_pt_radius(&rect, mval, margin);
|
||||
}
|
||||
|
||||
ViewDepths depth_temp = {0};
|
||||
view3d_update_depths_rect(region, &depth_temp, &rect);
|
||||
depth_close = view3d_depth_near(&depth_temp);
|
||||
float depth_close = view3d_depth_near(&depth_temp);
|
||||
MEM_SAFE_FREE(depth_temp.depths);
|
||||
return depth_close;
|
||||
}
|
||||
|
@ -1053,14 +1043,13 @@ bool ED_view3d_autodist(Depsgraph *depsgraph,
|
|||
{
|
||||
float depth_close;
|
||||
int margin_arr[] = {0, 2, 4};
|
||||
int i;
|
||||
bool depth_ok = false;
|
||||
|
||||
/* Get Z Depths, needed for perspective, nice for ortho */
|
||||
ED_view3d_draw_depth(depsgraph, region, v3d, alphaoverride);
|
||||
|
||||
/* Attempt with low margin's first */
|
||||
i = 0;
|
||||
int i = 0;
|
||||
do {
|
||||
depth_close = view_autodist_depth_margin(region, mval, margin_arr[i++] * U.pixelsize);
|
||||
depth_ok = (depth_close != FLT_MAX);
|
||||
|
@ -1104,9 +1093,8 @@ bool ED_view3d_autodist_simple(ARegion *region,
|
|||
int margin,
|
||||
const float *force_depth)
|
||||
{
|
||||
float depth;
|
||||
|
||||
/* Get Z Depths, needed for perspective, nice for ortho */
|
||||
float depth;
|
||||
if (force_depth) {
|
||||
depth = *force_depth;
|
||||
}
|
||||
|
@ -1237,7 +1225,6 @@ float ED_view3d_radius_to_dist(const View3D *v3d,
|
|||
}
|
||||
else {
|
||||
float lens, sensor_size, zoom;
|
||||
float angle;
|
||||
|
||||
if (persp == RV3D_CAMOB) {
|
||||
CameraParams params;
|
||||
|
@ -1259,7 +1246,7 @@ float ED_view3d_radius_to_dist(const View3D *v3d,
|
|||
zoom = CAMERA_PARAM_ZOOM_INIT_PERSP;
|
||||
}
|
||||
|
||||
angle = focallength_to_fov(lens, sensor_size);
|
||||
float angle = focallength_to_fov(lens, sensor_size);
|
||||
|
||||
/* zoom influences lens, correct this by scaling the angle as a distance
|
||||
* (by the zoom-level) */
|
||||
|
@ -1319,14 +1306,13 @@ float ED_view3d_offset_distance(const float mat[4][4],
|
|||
{
|
||||
float pos[4] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
float dir[4] = {0.0f, 0.0f, 1.0f, 0.0f};
|
||||
float dist;
|
||||
|
||||
mul_m4_v4(mat, pos);
|
||||
add_v3_v3(pos, ofs);
|
||||
mul_m4_v4(mat, dir);
|
||||
normalize_v3(dir);
|
||||
|
||||
dist = dot_v3v3(pos, dir);
|
||||
float dist = dot_v3v3(pos, dir);
|
||||
|
||||
if ((dist < FLT_EPSILON) && (fallback_dist != 0.0f)) {
|
||||
dist = fallback_dist;
|
||||
|
|
|
@ -77,8 +77,6 @@ static CLG_LogRef LOG = {"ed.undo"};
|
|||
enum eUndoStepDir {
|
||||
STEP_REDO = 1,
|
||||
STEP_UNDO = -1,
|
||||
/** Only used when the undo step name or index is passed to #ed_undo_step_impl. */
|
||||
STEP_NONE = 0,
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -180,19 +178,16 @@ void ED_undo_push(bContext *C, const char *str)
|
|||
}
|
||||
|
||||
/**
|
||||
* \note Also check #undo_history_exec in bottom if you change notifiers.
|
||||
* Common pre management of undo/redo (killing all running jobs, calling pre handlers, etc.).
|
||||
*/
|
||||
static int ed_undo_step_impl(bContext *C,
|
||||
enum eUndoStepDir step,
|
||||
const char *undo_name,
|
||||
const int undo_index,
|
||||
static void ed_undo_step_pre(bContext *C,
|
||||
wmWindowManager *wm,
|
||||
const enum eUndoStepDir undo_dir,
|
||||
ReportList *reports)
|
||||
{
|
||||
/* Mutually exclusives, ensure correct input. */
|
||||
BLI_assert(((undo_name || undo_index != -1) && (step == STEP_NONE)) ||
|
||||
(!(undo_name || undo_index != -1) && (step != STEP_NONE)));
|
||||
CLOG_INFO(&LOG, 1, "name='%s', index=%d, step=%d", undo_name, undo_index, step);
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
BLI_assert(ELEM(undo_dir, STEP_UNDO, STEP_REDO));
|
||||
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ScrArea *area = CTX_wm_area(C);
|
||||
|
||||
|
@ -201,22 +196,12 @@ static int ed_undo_step_impl(bContext *C,
|
|||
WM_jobs_kill_all(wm);
|
||||
|
||||
if (G.debug & G_DEBUG_IO) {
|
||||
Main *bmain = CTX_data_main(C);
|
||||
if (bmain->lock != NULL) {
|
||||
BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *BEFORE* undo step");
|
||||
BLO_main_validate_libraries(bmain, reports);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO(campbell): undo_system: use undo system */
|
||||
/* grease pencil can be can be used in plenty of spaces, so check it first */
|
||||
/* FIXME: This gpencil undo effectively only supports the one step undo/redo, undo based on name
|
||||
* or index is fully not implemented.
|
||||
* FIXME: However, it seems to never be used in current code (`ED_gpencil_session_active` seems
|
||||
* to always return false). */
|
||||
if (ED_gpencil_session_active()) {
|
||||
return ED_undo_gpencil_step(C, (int)step);
|
||||
}
|
||||
if (area && (area->spacetype == SPACE_VIEW3D)) {
|
||||
Object *obact = CTX_data_active_object(C);
|
||||
if (obact && (obact->type == OB_GPENCIL)) {
|
||||
|
@ -224,89 +209,40 @@ static int ed_undo_step_impl(bContext *C,
|
|||
}
|
||||
}
|
||||
|
||||
UndoStep *step_data_from_name = NULL;
|
||||
enum eUndoStepDir step_for_callback = step;
|
||||
if (undo_name != NULL) {
|
||||
step_data_from_name = BKE_undosys_step_find_by_name(wm->undo_stack, undo_name);
|
||||
if (step_data_from_name == NULL) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* TODO(campbell), could use simple optimization. */
|
||||
/* Pointers match on redo. */
|
||||
step_for_callback = (BLI_findindex(&wm->undo_stack->steps, step_data_from_name) <
|
||||
BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active)) ?
|
||||
STEP_UNDO :
|
||||
STEP_REDO;
|
||||
}
|
||||
else if (undo_index != -1) {
|
||||
step_for_callback = (undo_index <
|
||||
BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active)) ?
|
||||
STEP_UNDO :
|
||||
STEP_REDO;
|
||||
}
|
||||
|
||||
/* App-Handlers (pre). */
|
||||
{
|
||||
/* Note: ignore grease pencil for now. */
|
||||
Main *bmain = CTX_data_main(C);
|
||||
wm->op_undo_depth++;
|
||||
BKE_callback_exec_id(
|
||||
bmain, &scene->id, (step_for_callback > 0) ? BKE_CB_EVT_UNDO_PRE : BKE_CB_EVT_REDO_PRE);
|
||||
bmain, &scene->id, (undo_dir == STEP_UNDO) ? BKE_CB_EVT_UNDO_PRE : BKE_CB_EVT_REDO_PRE);
|
||||
wm->op_undo_depth--;
|
||||
}
|
||||
}
|
||||
|
||||
/* Undo System */
|
||||
{
|
||||
if (undo_name) {
|
||||
BKE_undosys_step_undo_with_data(wm->undo_stack, C, step_data_from_name);
|
||||
}
|
||||
else if (undo_index != -1) {
|
||||
BKE_undosys_step_undo_from_index(wm->undo_stack, C, undo_index);
|
||||
}
|
||||
else {
|
||||
if (step == STEP_UNDO) {
|
||||
BKE_undosys_step_undo(wm->undo_stack, C);
|
||||
}
|
||||
else {
|
||||
BKE_undosys_step_redo(wm->undo_stack, C);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Common post management of undo/redo (calling post handlers, adding notifiers etc.).
|
||||
*
|
||||
* \note Also check #undo_history_exec in bottom if you change notifiers.
|
||||
*/
|
||||
static void ed_undo_step_post(bContext *C,
|
||||
wmWindowManager *wm,
|
||||
const enum eUndoStepDir undo_dir,
|
||||
ReportList *reports)
|
||||
{
|
||||
BLI_assert(ELEM(undo_dir, STEP_UNDO, STEP_REDO));
|
||||
|
||||
/* Set special modes for grease pencil */
|
||||
if (area && (area->spacetype == SPACE_VIEW3D)) {
|
||||
Object *obact = CTX_data_active_object(C);
|
||||
if (obact && (obact->type == OB_GPENCIL)) {
|
||||
/* set cursor */
|
||||
if (ELEM(obact->mode,
|
||||
OB_MODE_PAINT_GPENCIL,
|
||||
OB_MODE_SCULPT_GPENCIL,
|
||||
OB_MODE_WEIGHT_GPENCIL,
|
||||
OB_MODE_VERTEX_GPENCIL)) {
|
||||
ED_gpencil_toggle_brush_cursor(C, true, NULL);
|
||||
}
|
||||
else {
|
||||
ED_gpencil_toggle_brush_cursor(C, false, NULL);
|
||||
}
|
||||
/* set workspace mode */
|
||||
Base *basact = CTX_data_active_base(C);
|
||||
ED_object_base_activate(C, basact);
|
||||
}
|
||||
}
|
||||
}
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
|
||||
/* App-Handlers (post). */
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
scene = CTX_data_scene(C);
|
||||
wm->op_undo_depth++;
|
||||
BKE_callback_exec_id(
|
||||
bmain, &scene->id, step_for_callback > 0 ? BKE_CB_EVT_UNDO_POST : BKE_CB_EVT_REDO_POST);
|
||||
bmain, &scene->id, (undo_dir == STEP_UNDO) ? BKE_CB_EVT_UNDO_POST : BKE_CB_EVT_REDO_POST);
|
||||
wm->op_undo_depth--;
|
||||
}
|
||||
|
||||
if (G.debug & G_DEBUG_IO) {
|
||||
Main *bmain = CTX_data_main(C);
|
||||
if (bmain->lock != NULL) {
|
||||
BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *AFTER* undo step");
|
||||
BLO_main_validate_libraries(bmain, reports);
|
||||
|
@ -317,30 +253,125 @@ static int ed_undo_step_impl(bContext *C,
|
|||
WM_event_add_notifier(C, NC_WM | ND_UNDO, NULL);
|
||||
|
||||
WM_toolsystem_refresh_active(C);
|
||||
|
||||
Main *bmain = CTX_data_main(C);
|
||||
WM_toolsystem_refresh_screen_all(bmain);
|
||||
|
||||
if (CLOG_CHECK(&LOG, 1)) {
|
||||
BKE_undosys_print(wm->undo_stack);
|
||||
}
|
||||
}
|
||||
|
||||
/** Undo or redo one step from current active one.
|
||||
* May undo or redo several steps at once only if the target step is a 'skipped' one.
|
||||
* The target step will be the one immediately before or after the active one. */
|
||||
static int ed_undo_step_direction(bContext *C, enum eUndoStepDir step, ReportList *reports)
|
||||
{
|
||||
BLI_assert(ELEM(step, STEP_UNDO, STEP_REDO));
|
||||
|
||||
CLOG_INFO(&LOG, 1, "direction=%s", (step == STEP_UNDO) ? "STEP_UNDO" : "STEP_REDO");
|
||||
|
||||
/* TODO(campbell): undo_system: use undo system */
|
||||
/* grease pencil can be can be used in plenty of spaces, so check it first */
|
||||
/* FIXME: This gpencil undo effectively only supports the one step undo/redo, undo based on name
|
||||
* or index is fully not implemented.
|
||||
* FIXME: However, it seems to never be used in current code (`ED_gpencil_session_active` seems
|
||||
* to always return false). */
|
||||
if (ED_gpencil_session_active()) {
|
||||
return ED_undo_gpencil_step(C, (int)step);
|
||||
}
|
||||
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
|
||||
ed_undo_step_pre(C, wm, step, reports);
|
||||
|
||||
if (step == STEP_UNDO) {
|
||||
BKE_undosys_step_undo(wm->undo_stack, C);
|
||||
}
|
||||
else {
|
||||
BKE_undosys_step_redo(wm->undo_stack, C);
|
||||
}
|
||||
|
||||
ed_undo_step_post(C, wm, step, reports);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static int ed_undo_step_direction(bContext *C, enum eUndoStepDir step, ReportList *reports)
|
||||
{
|
||||
return ed_undo_step_impl(C, step, NULL, -1, reports);
|
||||
}
|
||||
|
||||
/** Undo the step matching given name.
|
||||
* May undo several steps at once.
|
||||
* The target step will be the one immediately before given named one.
|
||||
* Only supposed to undo (will assert in case given named step is after current active one). */
|
||||
static int ed_undo_step_by_name(bContext *C, const char *undo_name, ReportList *reports)
|
||||
{
|
||||
return ed_undo_step_impl(C, STEP_NONE, undo_name, -1, reports);
|
||||
BLI_assert(undo_name != NULL);
|
||||
|
||||
/* FIXME: See comments in `ed_undo_step_direction`. */
|
||||
if (ED_gpencil_session_active()) {
|
||||
BLI_assert(!"Not implemented currently.");
|
||||
}
|
||||
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
UndoStep *undo_step_from_name = BKE_undosys_step_find_by_name(wm->undo_stack, undo_name);
|
||||
if (undo_step_from_name == NULL) {
|
||||
CLOG_ERROR(&LOG, "Step name='%s' not found in current undo stack", undo_name);
|
||||
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* TODO(campbell), could use simple optimization. */
|
||||
/* Pointers match on redo. */
|
||||
const int target_step_index = BLI_findindex(&wm->undo_stack->steps, undo_step_from_name);
|
||||
const int active_step_index = BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active);
|
||||
const enum eUndoStepDir undo_dir = (target_step_index < active_step_index) ? STEP_UNDO :
|
||||
STEP_REDO;
|
||||
|
||||
CLOG_INFO(&LOG,
|
||||
1,
|
||||
"name='%s', found direction=%s, index=%d",
|
||||
undo_name,
|
||||
(undo_dir == STEP_UNDO) ? "STEP_UNDO" : "STEP_REDO",
|
||||
target_step_index);
|
||||
|
||||
/* This function is currently not supposed to redo ever.
|
||||
* TODO: Will be fixed in future in continuing undo code refactor effort. */
|
||||
BLI_assert(undo_dir == STEP_UNDO);
|
||||
|
||||
ed_undo_step_pre(C, wm, undo_dir, reports);
|
||||
|
||||
BKE_undosys_step_undo_with_data(wm->undo_stack, C, undo_step_from_name);
|
||||
|
||||
ed_undo_step_post(C, wm, undo_dir, reports);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
/** Load the step matching given index in the stack.
|
||||
* May undo or redo several steps at once.
|
||||
* The target step will be the one indicated by the given index. */
|
||||
static int ed_undo_step_by_index(bContext *C, const int undo_index, ReportList *reports)
|
||||
{
|
||||
return ed_undo_step_impl(C, STEP_NONE, NULL, undo_index, reports);
|
||||
BLI_assert(undo_index >= 0);
|
||||
|
||||
/* FIXME: See comments in `ed_undo_step_direction`. */
|
||||
if (ED_gpencil_session_active()) {
|
||||
BLI_assert(!"Not implemented currently.");
|
||||
}
|
||||
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
const int active_step_index = BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active);
|
||||
const enum eUndoStepDir undo_dir = (undo_index < active_step_index) ? STEP_UNDO : STEP_REDO;
|
||||
|
||||
CLOG_INFO(&LOG,
|
||||
1,
|
||||
"index='%d', found direction=%s",
|
||||
undo_index,
|
||||
(undo_dir == STEP_UNDO) ? "STEP_UNDO" : "STEP_REDO");
|
||||
|
||||
ed_undo_step_pre(C, wm, undo_dir, reports);
|
||||
|
||||
BKE_undosys_step_undo_from_index(wm->undo_stack, C, undo_index);
|
||||
|
||||
ed_undo_step_post(C, wm, undo_dir, reports);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void ED_undo_grouped_push(bContext *C, const char *str)
|
||||
|
|
|
@ -114,7 +114,8 @@ void GPU_viewport_draw_to_screen(GPUViewport *viewport, int view, const rcti *re
|
|||
void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport,
|
||||
int view,
|
||||
const rcti *rect,
|
||||
bool display_colorspace);
|
||||
bool display_colorspace,
|
||||
bool do_overlay_merge);
|
||||
void GPU_viewport_free(GPUViewport *viewport);
|
||||
|
||||
void GPU_viewport_colorspace_set(GPUViewport *viewport,
|
||||
|
@ -125,7 +126,8 @@ void GPU_viewport_colorspace_set(GPUViewport *viewport,
|
|||
void GPU_viewport_bind_from_offscreen(GPUViewport *viewport, struct GPUOffScreen *ofs);
|
||||
void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport,
|
||||
struct GPUOffScreen *ofs,
|
||||
bool display_colorspace);
|
||||
bool display_colorspace,
|
||||
bool do_overlay_merge);
|
||||
|
||||
ViewportMemoryPool *GPU_viewport_mempool_get(GPUViewport *viewport);
|
||||
struct DRWInstanceDataList *GPU_viewport_instance_data_list_get(GPUViewport *viewport);
|
||||
|
|
|
@ -749,7 +749,8 @@ static void gpu_viewport_batch_free(GPUViewport *viewport)
|
|||
static void gpu_viewport_draw_colormanaged(GPUViewport *viewport,
|
||||
const rctf *rect_pos,
|
||||
const rctf *rect_uv,
|
||||
bool display_colorspace)
|
||||
bool display_colorspace,
|
||||
bool do_overlay_merge)
|
||||
{
|
||||
DefaultTextureList *dtxl = viewport->txl;
|
||||
GPUTexture *color = dtxl->color;
|
||||
|
@ -771,7 +772,7 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport,
|
|||
NULL,
|
||||
viewport->dither,
|
||||
false,
|
||||
true);
|
||||
do_overlay_merge);
|
||||
}
|
||||
|
||||
GPUBatch *batch = gpu_viewport_batch_get(viewport, rect_pos, rect_uv);
|
||||
|
@ -780,6 +781,7 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport,
|
|||
}
|
||||
else {
|
||||
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE);
|
||||
GPU_batch_uniform_1i(batch, "overlay", do_overlay_merge);
|
||||
GPU_batch_uniform_1i(batch, "display_transform", display_colorspace);
|
||||
GPU_batch_uniform_1i(batch, "image_texture", 0);
|
||||
GPU_batch_uniform_1i(batch, "overlays_texture", 1);
|
||||
|
@ -803,7 +805,8 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport,
|
|||
void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport,
|
||||
int view,
|
||||
const rcti *rect,
|
||||
bool display_colorspace)
|
||||
bool display_colorspace,
|
||||
bool do_overlay_merge)
|
||||
{
|
||||
gpu_viewport_framebuffer_view_set(viewport, view);
|
||||
DefaultFramebufferList *dfbl = viewport->fbl;
|
||||
|
@ -850,7 +853,8 @@ void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport,
|
|||
SWAP(float, uv_rect.ymin, uv_rect.ymax);
|
||||
}
|
||||
|
||||
gpu_viewport_draw_colormanaged(viewport, &pos_rect, &uv_rect, display_colorspace);
|
||||
gpu_viewport_draw_colormanaged(
|
||||
viewport, &pos_rect, &uv_rect, display_colorspace, do_overlay_merge);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -862,7 +866,7 @@ void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport,
|
|||
*/
|
||||
void GPU_viewport_draw_to_screen(GPUViewport *viewport, int view, const rcti *rect)
|
||||
{
|
||||
GPU_viewport_draw_to_screen_ex(viewport, view, rect, true);
|
||||
GPU_viewport_draw_to_screen_ex(viewport, view, rect, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -870,7 +874,8 @@ void GPU_viewport_draw_to_screen(GPUViewport *viewport, int view, const rcti *re
|
|||
*/
|
||||
void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport,
|
||||
struct GPUOffScreen *ofs,
|
||||
bool display_colorspace)
|
||||
bool display_colorspace,
|
||||
bool do_overlay_merge)
|
||||
{
|
||||
DefaultFramebufferList *dfbl = viewport->fbl;
|
||||
DefaultTextureList *dtxl = viewport->txl;
|
||||
|
@ -896,7 +901,8 @@ void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport,
|
|||
.ymax = 1.0f,
|
||||
};
|
||||
|
||||
gpu_viewport_draw_colormanaged(viewport, &pos_rect, &uv_rect, display_colorspace);
|
||||
gpu_viewport_draw_colormanaged(
|
||||
viewport, &pos_rect, &uv_rect, display_colorspace, do_overlay_merge);
|
||||
|
||||
/* This one is from the offscreen. Don't free it with the viewport. */
|
||||
dtxl->depth = NULL;
|
||||
|
|
|
@ -34,28 +34,6 @@
|
|||
|
||||
namespace blender::gpu {
|
||||
|
||||
/* See T82856: AMD drivers since 20.11 running on a polaris architecture doesn't support the
|
||||
* `GL_INT_2_10_10_10_REV` data type correctly. This data type is used to pack normals and flags.
|
||||
* The work around uses `GPU_RGBA16I` but that is only possible for loop normals.
|
||||
*
|
||||
* Vertex and Face normals would still render resulting in undefined behavior during selection and
|
||||
* rendering. */
|
||||
static bool is_faulty_T82856_platform(const char *version, const char *renderer)
|
||||
{
|
||||
/* On Linux the driver does not report its version. Test the OpenGL version in stead. */
|
||||
if (strstr(version, "4.5.14756") || strstr(version, "4.5.14757")) {
|
||||
if (strstr(renderer, " RX 460 ") || strstr(renderer, " RX 470 ") ||
|
||||
strstr(renderer, " RX 480 ") || strstr(renderer, " RX 490 ") ||
|
||||
strstr(renderer, " RX 560 ") || strstr(renderer, " RX 560X ") ||
|
||||
strstr(renderer, " RX 570 ") || strstr(renderer, " RX 580 ") ||
|
||||
strstr(renderer, " RX 590 ") || strstr(renderer, " RX550/550 ") ||
|
||||
strstr(renderer, " (TM) 520 ") || strstr(renderer, " (TM) 530 ") ||
|
||||
strstr(renderer, " R5 ") || strstr(renderer, " R7 ") || strstr(renderer, " R9 ")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Platform
|
||||
* \{ */
|
||||
|
@ -294,9 +272,17 @@ static void detect_workarounds()
|
|||
GCaps.broken_amd_driver = true;
|
||||
}
|
||||
/* See T82856: AMD drivers since 20.11 running on a polaris architecture doesn't support the
|
||||
* `GL_INT_2_10_10_10_REV` data type. */
|
||||
* `GL_INT_2_10_10_10_REV` data type correctly. This data type is used to pack normals and flags.
|
||||
* The work around uses `GPU_RGBA16I`.
|
||||
*/
|
||||
if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_OFFICIAL)) {
|
||||
if (is_faulty_T82856_platform(version, renderer)) {
|
||||
if (strstr(renderer, " RX 460 ") || strstr(renderer, " RX 470 ") ||
|
||||
strstr(renderer, " RX 480 ") || strstr(renderer, " RX 490 ") ||
|
||||
strstr(renderer, " RX 560 ") || strstr(renderer, " RX 560X ") ||
|
||||
strstr(renderer, " RX 570 ") || strstr(renderer, " RX 580 ") ||
|
||||
strstr(renderer, " RX 590 ") || strstr(renderer, " RX550/550 ") ||
|
||||
strstr(renderer, " (TM) 520 ") || strstr(renderer, " (TM) 530 ") ||
|
||||
strstr(renderer, " R5 ") || strstr(renderer, " R7 ") || strstr(renderer, " R9 ")) {
|
||||
GCaps.use_hq_normals_workaround = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
uniform sampler2D image_texture;
|
||||
uniform sampler2D overlays_texture;
|
||||
uniform bool display_transform;
|
||||
uniform bool overlay;
|
||||
|
||||
in vec2 texCoord_interp;
|
||||
|
||||
|
@ -30,12 +31,13 @@ void linearrgb_to_srgb(vec4 col_from, out vec4 col_to)
|
|||
void main()
|
||||
{
|
||||
fragColor = texture(image_texture, texCoord_interp.st);
|
||||
|
||||
vec4 overlay_col = texture(overlays_texture, texCoord_interp.st);
|
||||
|
||||
fragColor = clamp(fragColor, 0.0, 1.0);
|
||||
fragColor *= 1.0 - overlay_col.a;
|
||||
fragColor += overlay_col;
|
||||
if (overlay) {
|
||||
fragColor = clamp(fragColor, 0.0, 1.0);
|
||||
fragColor *= 1.0 - overlay_col.a;
|
||||
fragColor += overlay_col;
|
||||
}
|
||||
|
||||
if (display_transform) {
|
||||
linearrgb_to_srgb(fragColor, fragColor);
|
||||
|
|
|
@ -453,7 +453,7 @@ typedef enum ID_Type {
|
|||
ID_TXT = MAKE_ID2('T', 'X'), /* Text */
|
||||
ID_SPK = MAKE_ID2('S', 'K'), /* Speaker */
|
||||
ID_SO = MAKE_ID2('S', 'O'), /* Sound */
|
||||
ID_GR = MAKE_ID2('G', 'R'), /* Group */
|
||||
ID_GR = MAKE_ID2('G', 'R'), /* Collection */
|
||||
ID_AR = MAKE_ID2('A', 'R'), /* bArmature */
|
||||
ID_AC = MAKE_ID2('A', 'C'), /* bAction */
|
||||
ID_NT = MAKE_ID2('N', 'T'), /* bNodeTree */
|
||||
|
@ -472,7 +472,7 @@ typedef enum ID_Type {
|
|||
ID_HA = MAKE_ID2('H', 'A'), /* Hair */
|
||||
ID_PT = MAKE_ID2('P', 'T'), /* PointCloud */
|
||||
ID_VO = MAKE_ID2('V', 'O'), /* Volume */
|
||||
ID_SIM = MAKE_ID2('S', 'I'), /* Simulation (currently unused) */
|
||||
ID_SIM = MAKE_ID2('S', 'I'), /* Simulation (geometry node groups) */
|
||||
} ID_Type;
|
||||
|
||||
/* Only used as 'placeholder' in .blend files for directly linked data-blocks. */
|
||||
|
|
|
@ -440,7 +440,7 @@
|
|||
.renderlvl = 0, \
|
||||
.totlvl = 0, \
|
||||
.flags = eMultiresModifierFlag_UseCrease | eMultiresModifierFlag_ControlEdges, \
|
||||
.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS, \
|
||||
.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES, \
|
||||
.quality = 4, \
|
||||
.boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL, \
|
||||
}
|
||||
|
@ -622,7 +622,7 @@
|
|||
.levels = 1, \
|
||||
.renderLevels = 2, \
|
||||
.flags = eSubsurfModifierFlag_UseCrease | eSubsurfModifierFlag_ControlEdges, \
|
||||
.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS, \
|
||||
.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES, \
|
||||
.quality = 3, \
|
||||
.boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL, \
|
||||
.emCache = NULL, \
|
||||
|
|
|
@ -1089,14 +1089,15 @@ typedef struct NodeAttributeCompare {
|
|||
} NodeAttributeCompare;
|
||||
|
||||
typedef struct NodeAttributeMath {
|
||||
/* e.g. NODE_MATH_ADD. */
|
||||
/* NodeMathOperation. */
|
||||
uint8_t operation;
|
||||
|
||||
/* GeometryNodeAttributeInputMode */
|
||||
uint8_t input_type_a;
|
||||
uint8_t input_type_b;
|
||||
uint8_t input_type_c;
|
||||
|
||||
char _pad[5];
|
||||
char _pad[4];
|
||||
} NodeAttributeMath;
|
||||
|
||||
typedef struct NodeAttributeMix {
|
||||
|
@ -1183,6 +1184,15 @@ typedef struct NodeGeometryPointInstance {
|
|||
char _pad[6];
|
||||
} NodeGeometryPointInstance;
|
||||
|
||||
typedef struct NodeGeometryPointsToVolume {
|
||||
/* GeometryNodePointsToVolumeResolutionMode */
|
||||
uint8_t resolution_mode;
|
||||
/* GeometryNodeAttributeInputMode */
|
||||
uint8_t input_type_radius;
|
||||
|
||||
char _pad[6];
|
||||
} NodeGeometryPointsToVolume;
|
||||
|
||||
/* script node mode */
|
||||
#define NODE_SCRIPT_INTERNAL 0
|
||||
#define NODE_SCRIPT_EXTERNAL 1
|
||||
|
@ -1378,7 +1388,7 @@ enum {
|
|||
#define SHD_MATH_CLAMP 1
|
||||
|
||||
/* Math node operations. */
|
||||
enum {
|
||||
typedef enum NodeMathOperation {
|
||||
NODE_MATH_ADD = 0,
|
||||
NODE_MATH_SUBTRACT = 1,
|
||||
NODE_MATH_MULTIPLY = 2,
|
||||
|
@ -1419,7 +1429,7 @@ enum {
|
|||
NODE_MATH_PINGPONG = 37,
|
||||
NODE_MATH_SMOOTH_MIN = 38,
|
||||
NODE_MATH_SMOOTH_MAX = 39,
|
||||
};
|
||||
} NodeMathOperation;
|
||||
|
||||
/* Vector Math node operations. */
|
||||
typedef enum NodeVectorMathOperation {
|
||||
|
@ -1633,6 +1643,11 @@ typedef enum GeometryNodeTransformSpace {
|
|||
GEO_NODE_TRANSFORM_SPACE_RELATIVE = 1,
|
||||
} GeometryNodeTransformSpace;
|
||||
|
||||
typedef enum GeometryNodePointsToVolumeResolutionMode {
|
||||
GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT = 0,
|
||||
GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE = 1,
|
||||
} GeometryNodePointsToVolumeResolutionMode;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1632,33 +1632,35 @@ static IDProperty *rna_NodesModifier_properties(PointerRNA *ptr, bool create)
|
|||
static void rna_def_property_subdivision_common(StructRNA *srna)
|
||||
{
|
||||
static const EnumPropertyItem prop_uv_smooth_items[] = {
|
||||
{SUBSURF_UV_SMOOTH_NONE, "NONE", 0, "None", "UVs are not smoothed, boundaries are kept sharp"},
|
||||
{SUBSURF_UV_SMOOTH_PRESERVE_CORNERS,
|
||||
"PRESERVE_CORNERS",
|
||||
0,
|
||||
"Keep Corners",
|
||||
"UVs are smoothed, corners on discontinuous boundary are kept sharp"},
|
||||
# if 0
|
||||
{SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_AND_JUNCTIONS,
|
||||
"PRESERVE_CORNERS_AND_JUNCTIONS",
|
||||
0,
|
||||
"Smooth, keep corners+junctions",
|
||||
"UVs are smoothed, corners on discontinuous boundary and "
|
||||
"junctions of 3 or more regions are kept sharp"},
|
||||
{SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE,
|
||||
"PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE",
|
||||
0,
|
||||
"Smooth, keep corners+junctions+concave",
|
||||
"UVs are smoothed, corners on discontinuous boundary, "
|
||||
"junctions of 3 or more regions and darts and concave corners are kept sharp"},
|
||||
{SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES,
|
||||
"PRESERVE_BOUNDARIES",
|
||||
0,
|
||||
"Smooth, keep corners",
|
||||
"UVs are smoothed, boundaries are kept sharp"},
|
||||
# endif
|
||||
{SUBSURF_UV_SMOOTH_ALL, "PRESERVE_BOUNDARIES", 0, "All", "UVs and boundaries are smoothed"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
{SUBSURF_UV_SMOOTH_NONE,
|
||||
"NONE",
|
||||
0,
|
||||
"None",
|
||||
"UVs are not smoothed, boundaries are kept sharp"},
|
||||
{SUBSURF_UV_SMOOTH_PRESERVE_CORNERS,
|
||||
"PRESERVE_CORNERS",
|
||||
0,
|
||||
"Keep Corners",
|
||||
"UVs are smoothed, corners on discontinuous boundary are kept sharp"},
|
||||
{SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_AND_JUNCTIONS,
|
||||
"PRESERVE_CORNERS_AND_JUNCTIONS",
|
||||
0,
|
||||
"Keep Corners, Junctions",
|
||||
"UVs are smoothed, corners on discontinuous boundary and "
|
||||
"junctions of 3 or more regions are kept sharp"},
|
||||
{SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE,
|
||||
"PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE",
|
||||
0,
|
||||
"Keep Corners, Junctions, Concave",
|
||||
"UVs are smoothed, corners on discontinuous boundary, "
|
||||
"junctions of 3 or more regions and darts and concave corners are kept sharp"},
|
||||
{SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES,
|
||||
"PRESERVE_BOUNDARIES",
|
||||
0,
|
||||
"Keep boundaries",
|
||||
"UVs are smoothed, boundaries are kept sharp"},
|
||||
{SUBSURF_UV_SMOOTH_ALL, "SMOOTH_ALL", 0, "All", "UVs and boundaries are smoothed"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem prop_boundary_smooth_items[] = {
|
||||
|
|
|
@ -1980,22 +1980,6 @@ static const EnumPropertyItem *rna_GeometryNodeAttributeFill_domain_itemf(
|
|||
return itemf_function_check(rna_enum_attribute_domain_items, attribute_fill_domain_supported);
|
||||
}
|
||||
|
||||
static bool attribute_math_operation_supported(const EnumPropertyItem *item)
|
||||
{
|
||||
return ELEM(item->value,
|
||||
NODE_MATH_ADD,
|
||||
NODE_MATH_SUBTRACT,
|
||||
NODE_MATH_MULTIPLY,
|
||||
NODE_MATH_DIVIDE) &&
|
||||
(item->identifier[0] != '\0');
|
||||
}
|
||||
static const EnumPropertyItem *rna_GeometryNodeAttributeMath_operation_itemf(
|
||||
bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
|
||||
{
|
||||
*r_free = true;
|
||||
return itemf_function_check(rna_enum_node_math_items, attribute_math_operation_supported);
|
||||
}
|
||||
|
||||
/**
|
||||
* This bit of ugly code makes sure the float / attribute option shows up instead of
|
||||
* vector / attribute if the node uses an operation that uses a float for input B.
|
||||
|
@ -8579,10 +8563,9 @@ static void def_geo_attribute_math(StructRNA *srna)
|
|||
prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "operation");
|
||||
RNA_def_property_enum_items(prop, rna_enum_node_math_items);
|
||||
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeMath_operation_itemf");
|
||||
RNA_def_property_enum_default(prop, NODE_MATH_ADD);
|
||||
RNA_def_property_ui_text(prop, "Operation", "");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
|
||||
|
||||
prop = RNA_def_property(srna, "input_type_a", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_bitflag_sdna(prop, NULL, "input_type_a");
|
||||
|
@ -8595,6 +8578,12 @@ static void def_geo_attribute_math(StructRNA *srna)
|
|||
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
|
||||
RNA_def_property_ui_text(prop, "Input Type B", "");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
|
||||
|
||||
prop = RNA_def_property(srna, "input_type_c", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_bitflag_sdna(prop, NULL, "input_type_c");
|
||||
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
|
||||
RNA_def_property_ui_text(prop, "Input Type C", "");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
|
||||
}
|
||||
|
||||
static void def_geo_attribute_vector_math(StructRNA *srna)
|
||||
|
@ -8889,6 +8878,37 @@ static void def_geo_object_info(StructRNA *srna)
|
|||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
}
|
||||
|
||||
static void def_geo_points_to_volume(StructRNA *srna)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
static EnumPropertyItem resolution_mode_items[] = {
|
||||
{GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT,
|
||||
"VOXEL_AMOUNT",
|
||||
0,
|
||||
"Amount",
|
||||
"Specify the approximate number of voxels along the diagonal"},
|
||||
{GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE,
|
||||
"VOXEL_SIZE",
|
||||
0,
|
||||
"Size",
|
||||
"Specify the voxel side length"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
RNA_def_struct_sdna_from(srna, "NodeGeometryPointsToVolume", "storage");
|
||||
|
||||
prop = RNA_def_property(srna, "resolution_mode", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, resolution_mode_items);
|
||||
RNA_def_property_ui_text(prop, "Resolution Mode", "How the voxel size is specified");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
|
||||
|
||||
prop = RNA_def_property(srna, "input_type_radius", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
|
||||
RNA_def_property_ui_text(prop, "Radius Input Type", "");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static void rna_def_shader_node(BlenderRNA *brna)
|
||||
|
|
|
@ -85,16 +85,16 @@ const EnumPropertyItem rna_enum_object_mode_items[] = {
|
|||
ICON_GREASEPENCIL,
|
||||
"Draw",
|
||||
"Paint Grease Pencil Strokes"},
|
||||
{OB_MODE_VERTEX_GPENCIL,
|
||||
"VERTEX_GPENCIL",
|
||||
ICON_VPAINT_HLT,
|
||||
"Vertex Paint",
|
||||
"Grease Pencil Vertex Paint Strokes"},
|
||||
{OB_MODE_WEIGHT_GPENCIL,
|
||||
"WEIGHT_GPENCIL",
|
||||
ICON_WPAINT_HLT,
|
||||
"Weight Paint",
|
||||
"Grease Pencil Weight Paint Strokes"},
|
||||
{OB_MODE_VERTEX_GPENCIL,
|
||||
"VERTEX_GPENCIL",
|
||||
ICON_VPAINT_HLT,
|
||||
"Vertex Paint",
|
||||
"Grease Pencil Vertex Paint Strokes"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
|
|
|
@ -927,9 +927,10 @@ static void rna_Sequence_filepath_update(Main *bmain, Scene *UNUSED(scene), Poin
|
|||
rna_Sequence_invalidate_raw_update(bmain, scene, ptr);
|
||||
}
|
||||
|
||||
static void rna_Sequence_sound_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
|
||||
static void rna_Sequence_sound_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr))
|
||||
{
|
||||
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS | ID_RECALC_AUDIO);
|
||||
DEG_relations_tag_update(bmain);
|
||||
}
|
||||
|
||||
static int seqproxy_seq_cmp_fn(Sequence *seq, void *arg_pt)
|
||||
|
|
|
@ -160,6 +160,7 @@ set(SRC
|
|||
geometry/nodes/node_geo_point_scale.cc
|
||||
geometry/nodes/node_geo_point_separate.cc
|
||||
geometry/nodes/node_geo_point_translate.cc
|
||||
geometry/nodes/node_geo_points_to_volume.cc
|
||||
geometry/nodes/node_geo_subdivision_surface.cc
|
||||
geometry/nodes/node_geo_transform.cc
|
||||
geometry/nodes/node_geo_triangulate.cc
|
||||
|
|
|
@ -48,6 +48,7 @@ void register_node_type_geo_attribute_color_ramp(void);
|
|||
void register_node_type_geo_point_rotate(void);
|
||||
void register_node_type_geo_align_rotation_to_vector(void);
|
||||
void register_node_type_geo_sample_texture(void);
|
||||
void register_node_type_geo_points_to_volume(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -290,6 +290,7 @@ DefNode(GeometryNode, GEO_NODE_ALIGN_ROTATION_TO_VECTOR, def_geo_align_rotation_
|
|||
DefNode(GeometryNode, GEO_NODE_POINT_SCALE, def_geo_point_scale, "POINT_SCALE", PointScale, "Point Scale", "")
|
||||
DefNode(GeometryNode, GEO_NODE_POINT_TRANSLATE, def_geo_point_translate, "POINT_TRANSLATE", PointTranslate, "Point Translate", "")
|
||||
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE, def_geo_attribute_sample_texture, "ATTRIBUTE_SAMPLE_TEXTURE", AttributeSampleTexture, "Attribute Sample Texture", "")
|
||||
DefNode(GeometryNode, GEO_NODE_POINTS_TO_VOLUME, def_geo_points_to_volume, "POINTS_TO_VOLUME", PointsToVolume, "Points to Volume", "")
|
||||
|
||||
/* undefine macros */
|
||||
#undef DefNode
|
||||
|
|
|
@ -54,6 +54,8 @@ static int attribute_data_type_complexity(const CustomDataType data_type)
|
|||
return 1;
|
||||
case CD_PROP_FLOAT:
|
||||
return 2;
|
||||
case CD_PROP_FLOAT2:
|
||||
return 3;
|
||||
case CD_PROP_FLOAT3:
|
||||
return 4;
|
||||
case CD_PROP_COLOR:
|
||||
|
|
|
@ -34,6 +34,8 @@ static bNodeSocketTemplate geo_node_attribute_math_in[] = {
|
|||
{SOCK_FLOAT, N_("A"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
|
||||
{SOCK_STRING, N_("B")},
|
||||
{SOCK_FLOAT, N_("B"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
|
||||
{SOCK_STRING, N_("C")},
|
||||
{SOCK_FLOAT, N_("C"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
|
||||
{SOCK_STRING, N_("Result")},
|
||||
{-1, ""},
|
||||
};
|
||||
|
@ -51,45 +53,132 @@ static void geo_node_attribute_math_init(bNodeTree *UNUSED(tree), bNode *node)
|
|||
data->operation = NODE_MATH_ADD;
|
||||
data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
|
||||
data->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
|
||||
data->input_type_c = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
|
||||
node->storage = data;
|
||||
}
|
||||
|
||||
static bool operation_use_input_c(const NodeMathOperation operation)
|
||||
{
|
||||
return ELEM(operation,
|
||||
NODE_MATH_MULTIPLY_ADD,
|
||||
NODE_MATH_SMOOTH_MIN,
|
||||
NODE_MATH_SMOOTH_MAX,
|
||||
NODE_MATH_WRAP,
|
||||
NODE_MATH_COMPARE);
|
||||
}
|
||||
|
||||
static bool operation_use_input_b(const NodeMathOperation operation)
|
||||
{
|
||||
switch (operation) {
|
||||
case NODE_MATH_ADD:
|
||||
case NODE_MATH_SUBTRACT:
|
||||
case NODE_MATH_MULTIPLY:
|
||||
case NODE_MATH_DIVIDE:
|
||||
case NODE_MATH_POWER:
|
||||
case NODE_MATH_LOGARITHM:
|
||||
case NODE_MATH_MINIMUM:
|
||||
case NODE_MATH_MAXIMUM:
|
||||
case NODE_MATH_LESS_THAN:
|
||||
case NODE_MATH_GREATER_THAN:
|
||||
case NODE_MATH_MODULO:
|
||||
case NODE_MATH_ARCTAN2:
|
||||
case NODE_MATH_SNAP:
|
||||
case NODE_MATH_WRAP:
|
||||
case NODE_MATH_COMPARE:
|
||||
case NODE_MATH_MULTIPLY_ADD:
|
||||
case NODE_MATH_PINGPONG:
|
||||
case NODE_MATH_SMOOTH_MIN:
|
||||
case NODE_MATH_SMOOTH_MAX:
|
||||
return true;
|
||||
case NODE_MATH_SINE:
|
||||
case NODE_MATH_COSINE:
|
||||
case NODE_MATH_TANGENT:
|
||||
case NODE_MATH_ARCSINE:
|
||||
case NODE_MATH_ARCCOSINE:
|
||||
case NODE_MATH_ARCTANGENT:
|
||||
case NODE_MATH_ROUND:
|
||||
case NODE_MATH_ABSOLUTE:
|
||||
case NODE_MATH_FLOOR:
|
||||
case NODE_MATH_CEIL:
|
||||
case NODE_MATH_FRACTION:
|
||||
case NODE_MATH_SQRT:
|
||||
case NODE_MATH_INV_SQRT:
|
||||
case NODE_MATH_SIGN:
|
||||
case NODE_MATH_EXPONENT:
|
||||
case NODE_MATH_RADIANS:
|
||||
case NODE_MATH_DEGREES:
|
||||
case NODE_MATH_SINH:
|
||||
case NODE_MATH_COSH:
|
||||
case NODE_MATH_TANH:
|
||||
case NODE_MATH_TRUNC:
|
||||
return false;
|
||||
}
|
||||
BLI_assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
static void geo_node_attribute_math_update(bNodeTree *UNUSED(ntree), bNode *node)
|
||||
{
|
||||
NodeAttributeMath *node_storage = (NodeAttributeMath *)node->storage;
|
||||
NodeAttributeMath &node_storage = *(NodeAttributeMath *)node->storage;
|
||||
NodeMathOperation operation = static_cast<NodeMathOperation>(node_storage.operation);
|
||||
|
||||
update_attribute_input_socket_availabilities(
|
||||
*node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a);
|
||||
*node, "A", (GeometryNodeAttributeInputMode)node_storage.input_type_a);
|
||||
update_attribute_input_socket_availabilities(
|
||||
*node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b);
|
||||
*node,
|
||||
"B",
|
||||
(GeometryNodeAttributeInputMode)node_storage.input_type_b,
|
||||
operation_use_input_b(operation));
|
||||
update_attribute_input_socket_availabilities(
|
||||
*node,
|
||||
"C",
|
||||
(GeometryNodeAttributeInputMode)node_storage.input_type_c,
|
||||
operation_use_input_c(operation));
|
||||
}
|
||||
|
||||
static void do_math_operation(const FloatReadAttribute &input_a,
|
||||
const FloatReadAttribute &input_b,
|
||||
FloatWriteAttribute result,
|
||||
const int operation)
|
||||
static void do_math_operation(Span<float> span_a,
|
||||
Span<float> span_b,
|
||||
Span<float> span_c,
|
||||
MutableSpan<float> span_result,
|
||||
const NodeMathOperation operation)
|
||||
{
|
||||
const int size = input_a.size();
|
||||
|
||||
Span<float> span_a = input_a.get_span();
|
||||
Span<float> span_b = input_b.get_span();
|
||||
MutableSpan<float> span_result = result.get_span_for_write_only();
|
||||
|
||||
bool success = try_dispatch_float_math_fl_fl_to_fl(
|
||||
bool success = try_dispatch_float_math_fl_fl_fl_to_fl(
|
||||
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
|
||||
for (const int i : IndexRange(size)) {
|
||||
const float in1 = span_a[i];
|
||||
const float in2 = span_b[i];
|
||||
const float out = math_function(in1, in2);
|
||||
span_result[i] = out;
|
||||
for (const int i : IndexRange(span_result.size())) {
|
||||
span_result[i] = math_function(span_a[i], span_b[i], span_c[i]);
|
||||
}
|
||||
});
|
||||
BLI_assert(success);
|
||||
UNUSED_VARS_NDEBUG(success);
|
||||
}
|
||||
|
||||
result.apply_span();
|
||||
static void do_math_operation(Span<float> span_a,
|
||||
Span<float> span_b,
|
||||
MutableSpan<float> span_result,
|
||||
const NodeMathOperation operation)
|
||||
{
|
||||
bool success = try_dispatch_float_math_fl_fl_to_fl(
|
||||
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
|
||||
for (const int i : IndexRange(span_result.size())) {
|
||||
span_result[i] = math_function(span_a[i], span_b[i]);
|
||||
}
|
||||
});
|
||||
BLI_assert(success);
|
||||
UNUSED_VARS_NDEBUG(success);
|
||||
}
|
||||
|
||||
/* The operation is not supported by this node currently. */
|
||||
static void do_math_operation(Span<float> span_input,
|
||||
MutableSpan<float> span_result,
|
||||
const NodeMathOperation operation)
|
||||
{
|
||||
bool success = try_dispatch_float_math_fl_to_fl(
|
||||
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
|
||||
for (const int i : IndexRange(span_result.size())) {
|
||||
span_result[i] = math_function(span_input[i]);
|
||||
}
|
||||
});
|
||||
BLI_assert(success);
|
||||
UNUSED_VARS_NDEBUG(success);
|
||||
}
|
||||
|
@ -98,7 +187,7 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP
|
|||
{
|
||||
const bNode &node = params.node();
|
||||
const NodeAttributeMath *node_storage = (const NodeAttributeMath *)node.storage;
|
||||
const int operation = node_storage->operation;
|
||||
const NodeMathOperation operation = static_cast<NodeMathOperation>(node_storage->operation);
|
||||
|
||||
/* The result type of this node is always float. */
|
||||
const CustomDataType result_type = CD_PROP_FLOAT;
|
||||
|
@ -115,15 +204,44 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP
|
|||
|
||||
ReadAttributePtr attribute_a = params.get_input_attribute(
|
||||
"A", component, result_domain, result_type, nullptr);
|
||||
ReadAttributePtr attribute_b = params.get_input_attribute(
|
||||
"B", component, result_domain, result_type, nullptr);
|
||||
if (!attribute_a || !attribute_b) {
|
||||
/* Attribute wasn't found. */
|
||||
if (!attribute_a) {
|
||||
return;
|
||||
}
|
||||
|
||||
do_math_operation(*attribute_a, *attribute_b, *attribute_result, operation);
|
||||
attribute_result.save();
|
||||
/* Note that passing the data with `get_span<float>()` works
|
||||
* because the attributes were accessed with #CD_PROP_FLOAT. */
|
||||
if (operation_use_input_b(operation)) {
|
||||
ReadAttributePtr attribute_b = params.get_input_attribute(
|
||||
"B", component, result_domain, result_type, nullptr);
|
||||
if (!attribute_b) {
|
||||
return;
|
||||
}
|
||||
if (operation_use_input_c(operation)) {
|
||||
ReadAttributePtr attribute_c = params.get_input_attribute(
|
||||
"C", component, result_domain, result_type, nullptr);
|
||||
if (!attribute_c) {
|
||||
return;
|
||||
}
|
||||
do_math_operation(attribute_a->get_span<float>(),
|
||||
attribute_b->get_span<float>(),
|
||||
attribute_c->get_span<float>(),
|
||||
attribute_result->get_span_for_write_only<float>(),
|
||||
operation);
|
||||
}
|
||||
else {
|
||||
do_math_operation(attribute_a->get_span<float>(),
|
||||
attribute_b->get_span<float>(),
|
||||
attribute_result->get_span_for_write_only<float>(),
|
||||
operation);
|
||||
}
|
||||
}
|
||||
else {
|
||||
do_math_operation(attribute_a->get_span<float>(),
|
||||
attribute_result->get_span_for_write_only<float>(),
|
||||
operation);
|
||||
}
|
||||
|
||||
attribute_result.apply_span_and_save();
|
||||
}
|
||||
|
||||
static void geo_node_attribute_math_exec(GeoNodeExecParams params)
|
||||
|
|
|
@ -43,18 +43,32 @@ static Mesh *join_mesh_topology_and_builtin_attributes(Span<const MeshComponent
|
|||
int totedges = 0;
|
||||
int totpolys = 0;
|
||||
|
||||
int64_t cd_dirty_vert = 0;
|
||||
int64_t cd_dirty_poly = 0;
|
||||
int64_t cd_dirty_edge = 0;
|
||||
int64_t cd_dirty_loop = 0;
|
||||
|
||||
for (const MeshComponent *mesh_component : src_components) {
|
||||
const Mesh *mesh = mesh_component->get_for_read();
|
||||
totverts += mesh->totvert;
|
||||
totloops += mesh->totloop;
|
||||
totedges += mesh->totedge;
|
||||
totpolys += mesh->totpoly;
|
||||
cd_dirty_vert |= mesh->runtime.cd_dirty_vert;
|
||||
cd_dirty_poly |= mesh->runtime.cd_dirty_poly;
|
||||
cd_dirty_edge |= mesh->runtime.cd_dirty_edge;
|
||||
cd_dirty_loop |= mesh->runtime.cd_dirty_loop;
|
||||
}
|
||||
|
||||
const Mesh *first_input_mesh = src_components[0]->get_for_read();
|
||||
Mesh *new_mesh = BKE_mesh_new_nomain(totverts, totedges, 0, totloops, totpolys);
|
||||
BKE_mesh_copy_settings(new_mesh, first_input_mesh);
|
||||
|
||||
new_mesh->runtime.cd_dirty_vert = cd_dirty_vert;
|
||||
new_mesh->runtime.cd_dirty_poly = cd_dirty_poly;
|
||||
new_mesh->runtime.cd_dirty_edge = cd_dirty_edge;
|
||||
new_mesh->runtime.cd_dirty_loop = cd_dirty_loop;
|
||||
|
||||
int vert_offset = 0;
|
||||
int loop_offset = 0;
|
||||
int edge_offset = 0;
|
||||
|
@ -124,17 +138,17 @@ static void determine_final_data_type_and_domain(Span<const GeometryComponent *>
|
|||
CustomDataType *r_type,
|
||||
AttributeDomain *r_domain)
|
||||
{
|
||||
Vector<CustomDataType> data_types;
|
||||
for (const GeometryComponent *component : components) {
|
||||
ReadAttributePtr attribute = component->attribute_try_get_for_read(attribute_name);
|
||||
if (attribute) {
|
||||
/* TODO: Use data type with most information. */
|
||||
*r_type = bke::cpp_type_to_custom_data_type(attribute->cpp_type());
|
||||
data_types.append(attribute->custom_data_type());
|
||||
/* TODO: Use highest priority domain. */
|
||||
*r_domain = attribute->domain();
|
||||
return;
|
||||
}
|
||||
}
|
||||
BLI_assert(false);
|
||||
|
||||
*r_type = attribute_data_type_highest_complexity(data_types);
|
||||
}
|
||||
|
||||
static void fill_new_attribute(Span<const GeometryComponent *> src_components,
|
||||
|
@ -219,11 +233,9 @@ static void join_components(Span<const InstancesComponent *> src_components, Geo
|
|||
for (const InstancesComponent *component : src_components) {
|
||||
const int size = component->instances_amount();
|
||||
Span<InstancedData> instanced_data = component->instanced_data();
|
||||
Span<float3> positions = component->positions();
|
||||
Span<float3> rotations = component->rotations();
|
||||
Span<float3> scales = component->scales();
|
||||
Span<float4x4> transforms = component->transforms();
|
||||
for (const int i : IndexRange(size)) {
|
||||
dst_component.add_instance(instanced_data[i], positions[i], rotations[i], scales[i]);
|
||||
dst_component.add_instance(instanced_data[i], transforms[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,10 +91,12 @@ static void geo_node_object_info_exec(GeoNodeExecParams params)
|
|||
InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
|
||||
|
||||
if (transform_space_relative) {
|
||||
instances.add_instance(object, location, rotation, scale);
|
||||
instances.add_instance(object, transform);
|
||||
}
|
||||
else {
|
||||
instances.add_instance(object, {0, 0, 0});
|
||||
float unit_transform[4][4];
|
||||
unit_m4(unit_transform);
|
||||
instances.add_instance(object, unit_transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -171,7 +171,9 @@ static void add_instances_from_geometry_component(InstancesComponent &instances,
|
|||
|
||||
for (const int i : IndexRange(domain_size)) {
|
||||
if (instances_data[i].has_value()) {
|
||||
instances.add_instance(*instances_data[i], positions[i], rotations[i], scales[i], ids[i]);
|
||||
float transform[4][4];
|
||||
loc_eul_size_to_mat4(transform, positions[i], rotations[i], scales[i]);
|
||||
instances.add_instance(*instances_data[i], transform, ids[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef WITH_OPENVDB
|
||||
# include <openvdb/openvdb.h>
|
||||
# include <openvdb/tools/LevelSetUtil.h>
|
||||
# include <openvdb/tools/ParticlesToLevelSet.h>
|
||||
#endif
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_volume.h"
|
||||
|
||||
static bNodeSocketTemplate geo_node_points_to_volume_in[] = {
|
||||
{SOCK_GEOMETRY, N_("Geometry")},
|
||||
{SOCK_FLOAT, N_("Density"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX},
|
||||
{SOCK_FLOAT, N_("Voxel Size"), 0.3f, 0.0f, 0.0f, 0.0f, 0.01f, FLT_MAX},
|
||||
{SOCK_FLOAT, N_("Voxel Amount"), 64.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX},
|
||||
{SOCK_STRING, N_("Radius")},
|
||||
{SOCK_FLOAT, N_("Radius"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX},
|
||||
{-1, ""},
|
||||
};
|
||||
|
||||
static bNodeSocketTemplate geo_node_point_translate_out[] = {
|
||||
{SOCK_GEOMETRY, N_("Geometry")},
|
||||
{-1, ""},
|
||||
};
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
#ifdef WITH_OPENVDB
|
||||
namespace {
|
||||
/* Implements the interface required by #openvdb::tools::ParticlesToLevelSet. */
|
||||
struct ParticleList {
|
||||
using PosType = openvdb::Vec3R;
|
||||
|
||||
Span<float3> positions;
|
||||
Span<float> radii;
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return (size_t)positions.size();
|
||||
}
|
||||
|
||||
void getPos(size_t n, openvdb::Vec3R &xyz) const
|
||||
{
|
||||
xyz = &positions[n].x;
|
||||
}
|
||||
|
||||
void getPosRad(size_t n, openvdb::Vec3R &xyz, openvdb::Real &radius) const
|
||||
{
|
||||
xyz = &positions[n].x;
|
||||
radius = radii[n];
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
static openvdb::FloatGrid::Ptr generate_volume_from_points(const Span<float3> positions,
|
||||
const Span<float> radii,
|
||||
const float density)
|
||||
{
|
||||
/* Create a new grid that will be filled. #ParticlesToLevelSet requires the background value to
|
||||
* be positive. It will be set to zero later on. */
|
||||
openvdb::FloatGrid::Ptr new_grid = openvdb::FloatGrid::create(1.0f);
|
||||
|
||||
/* Create a narrow-band level set grid based on the positions and radii. */
|
||||
openvdb::tools::ParticlesToLevelSet op{*new_grid};
|
||||
/* Don't ignore particles based on their radius. */
|
||||
op.setRmin(0.0f);
|
||||
op.setRmax(FLT_MAX);
|
||||
ParticleList particles{positions, radii};
|
||||
op.rasterizeSpheres(particles);
|
||||
op.finalize();
|
||||
|
||||
/* Convert the level set to a fog volume. This also sets the background value to zero. Inside the
|
||||
* fog there will be a density of 1. */
|
||||
openvdb::tools::sdfToFogVolume(*new_grid);
|
||||
|
||||
/* Take the desired density into account. */
|
||||
openvdb::tools::foreach (new_grid->beginValueOn(),
|
||||
[&](const openvdb::FloatGrid::ValueOnIter &iter) {
|
||||
iter.modifyValue([&](float &value) { value *= density; });
|
||||
});
|
||||
return new_grid;
|
||||
}
|
||||
|
||||
static float compute_voxel_size(const GeoNodeExecParams ¶ms,
|
||||
Span<float3> positions,
|
||||
const float radius)
|
||||
{
|
||||
const NodeGeometryPointsToVolume &storage =
|
||||
*(const NodeGeometryPointsToVolume *)params.node().storage;
|
||||
|
||||
if (storage.resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE) {
|
||||
return params.get_input<float>("Voxel Size");
|
||||
}
|
||||
|
||||
if (positions.is_empty()) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
float3 min, max;
|
||||
INIT_MINMAX(min, max);
|
||||
minmax_v3v3_v3_array(min, max, (float(*)[3])positions.data(), positions.size());
|
||||
|
||||
const float voxel_amount = params.get_input<float>("Voxel Amount");
|
||||
if (voxel_amount <= 1) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/* The voxel size adapts to the final size of the volume. */
|
||||
const float diagonal = float3::distance(min, max);
|
||||
const float extended_diagonal = diagonal + 2.0f * radius;
|
||||
const float voxel_size = extended_diagonal / voxel_amount;
|
||||
return voxel_size;
|
||||
}
|
||||
|
||||
static void gather_point_data_from_component(const GeoNodeExecParams ¶ms,
|
||||
const GeometryComponent &component,
|
||||
Vector<float3> &r_positions,
|
||||
Vector<float> &r_radii)
|
||||
{
|
||||
Float3ReadAttribute positions = component.attribute_get_for_read<float3>(
|
||||
"position", ATTR_DOMAIN_POINT, {0, 0, 0});
|
||||
FloatReadAttribute radii = params.get_input_attribute<float>(
|
||||
"Radius", component, ATTR_DOMAIN_POINT, 0.0f);
|
||||
|
||||
r_positions.extend(positions.get_span());
|
||||
r_radii.extend(radii.get_span());
|
||||
}
|
||||
|
||||
static void convert_to_grid_index_space(const float voxel_size,
|
||||
MutableSpan<float3> positions,
|
||||
MutableSpan<float> radii)
|
||||
{
|
||||
const float voxel_size_inv = 1.0f / voxel_size;
|
||||
for (const int i : positions.index_range()) {
|
||||
positions[i] *= voxel_size_inv;
|
||||
/* Better align generated grid with source points. */
|
||||
positions[i] -= float3(0.5f);
|
||||
radii[i] *= voxel_size_inv;
|
||||
}
|
||||
}
|
||||
|
||||
static void initialize_volume_component_from_points(const GeometrySet &geometry_set_in,
|
||||
GeometrySet &geometry_set_out,
|
||||
const GeoNodeExecParams ¶ms)
|
||||
{
|
||||
Vector<float3> positions;
|
||||
Vector<float> radii;
|
||||
|
||||
if (geometry_set_in.has<MeshComponent>()) {
|
||||
gather_point_data_from_component(
|
||||
params, *geometry_set_in.get_component_for_read<MeshComponent>(), positions, radii);
|
||||
}
|
||||
if (geometry_set_in.has<PointCloudComponent>()) {
|
||||
gather_point_data_from_component(
|
||||
params, *geometry_set_in.get_component_for_read<PointCloudComponent>(), positions, radii);
|
||||
}
|
||||
|
||||
const float max_radius = *std::max_element(radii.begin(), radii.end());
|
||||
const float voxel_size = compute_voxel_size(params, positions, max_radius);
|
||||
if (voxel_size == 0.0f || positions.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Volume *volume = (Volume *)BKE_id_new_nomain(ID_VO, nullptr);
|
||||
BKE_volume_init_grids(volume);
|
||||
|
||||
VolumeGrid *c_density_grid = BKE_volume_grid_add(volume, "density", VOLUME_GRID_FLOAT);
|
||||
openvdb::FloatGrid::Ptr density_grid = openvdb::gridPtrCast<openvdb::FloatGrid>(
|
||||
BKE_volume_grid_openvdb_for_write(volume, c_density_grid, false));
|
||||
|
||||
const float density = params.get_input<float>("Density");
|
||||
convert_to_grid_index_space(voxel_size, positions, radii);
|
||||
openvdb::FloatGrid::Ptr new_grid = generate_volume_from_points(positions, radii, density);
|
||||
/* This merge is cheap, because the #density_grid is empty. */
|
||||
density_grid->merge(*new_grid);
|
||||
density_grid->transform().postScale(voxel_size);
|
||||
|
||||
VolumeComponent &volume_component = geometry_set_out.get_component_for_write<VolumeComponent>();
|
||||
volume_component.replace(volume);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void geo_node_points_to_volume_exec(GeoNodeExecParams params)
|
||||
{
|
||||
GeometrySet geometry_set_in = params.extract_input<GeometrySet>("Geometry");
|
||||
GeometrySet geometry_set_out;
|
||||
|
||||
#ifdef WITH_OPENVDB
|
||||
initialize_volume_component_from_points(geometry_set_in, geometry_set_out, params);
|
||||
#endif
|
||||
|
||||
params.set_output("Geometry", std::move(geometry_set_out));
|
||||
}
|
||||
|
||||
static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node)
|
||||
{
|
||||
NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)MEM_callocN(
|
||||
sizeof(NodeGeometryPointsToVolume), __func__);
|
||||
data->resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT;
|
||||
data->input_type_radius = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
|
||||
node->storage = data;
|
||||
|
||||
bNodeSocket *radius_attribute_socket = nodeFindSocket(node, SOCK_IN, "Radius");
|
||||
bNodeSocketValueString *radius_attribute_socket_value =
|
||||
(bNodeSocketValueString *)radius_attribute_socket->default_value;
|
||||
STRNCPY(radius_attribute_socket_value->value, "radius");
|
||||
}
|
||||
|
||||
static void geo_node_points_to_volume_update(bNodeTree *UNUSED(ntree), bNode *node)
|
||||
{
|
||||
NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)node->storage;
|
||||
bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size");
|
||||
bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount");
|
||||
nodeSetSocketAvailability(voxel_amount_socket,
|
||||
data->resolution_mode ==
|
||||
GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT);
|
||||
nodeSetSocketAvailability(
|
||||
voxel_size_socket, data->resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE);
|
||||
|
||||
update_attribute_input_socket_availabilities(
|
||||
*node, "Radius", (GeometryNodeAttributeInputMode)data->input_type_radius);
|
||||
}
|
||||
|
||||
} // namespace blender::nodes
|
||||
|
||||
void register_node_type_geo_points_to_volume()
|
||||
{
|
||||
static bNodeType ntype;
|
||||
|
||||
geo_node_type_base(
|
||||
&ntype, GEO_NODE_POINTS_TO_VOLUME, "Points to Volume", NODE_CLASS_GEOMETRY, 0);
|
||||
node_type_socket_templates(&ntype, geo_node_points_to_volume_in, geo_node_point_translate_out);
|
||||
node_type_storage(&ntype,
|
||||
"NodeGeometryPointsToVolume",
|
||||
node_free_standard_storage,
|
||||
node_copy_standard_storage);
|
||||
node_type_size(&ntype, 170, 120, 700);
|
||||
node_type_init(&ntype, blender::nodes::geo_node_points_to_volume_init);
|
||||
node_type_update(&ntype, blender::nodes::geo_node_points_to_volume_update);
|
||||
ntype.geometry_node_execute = blender::nodes::geo_node_points_to_volume_exec;
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
|
@ -99,27 +99,20 @@ static void transform_instances(InstancesComponent &instances,
|
|||
const float3 rotation,
|
||||
const float3 scale)
|
||||
{
|
||||
MutableSpan<float3> positions = instances.positions();
|
||||
MutableSpan<float3> rotations = instances.rotations();
|
||||
MutableSpan<float3> scales = instances.scales();
|
||||
MutableSpan<float4x4> transforms = instances.transforms();
|
||||
|
||||
/* Use only translation if rotation and scale don't apply. */
|
||||
if (use_translate(rotation, scale)) {
|
||||
for (float3 &position : positions) {
|
||||
add_v3_v3(position, translation);
|
||||
for (float4x4 &transform : transforms) {
|
||||
add_v3_v3(transform.ptr()[3], translation);
|
||||
}
|
||||
}
|
||||
else {
|
||||
float mat[4][4];
|
||||
float instance_mat[4][4];
|
||||
float quaternion[4];
|
||||
|
||||
loc_eul_size_to_mat4(mat, translation, rotation, scale);
|
||||
for (int i = 0; i < positions.size(); i++) {
|
||||
loc_eul_size_to_mat4(instance_mat, positions[i], rotations[i], scales[i]);
|
||||
mul_m4_m4_pre(instance_mat, mat);
|
||||
mat4_decompose(positions[i], quaternion, scales[i], instance_mat);
|
||||
quat_to_eul(rotations[i], quaternion);
|
||||
for (float4x4 &transform : transforms) {
|
||||
mul_m4_m4_pre(transform.ptr(), mat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -768,7 +768,7 @@ static void *init_heights_data(MultiresBakeRender *bkr, Image *ima)
|
|||
|
||||
if (ss_lvl > 0) {
|
||||
smd.levels = smd.renderLevels = ss_lvl;
|
||||
smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS;
|
||||
smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES;
|
||||
smd.quality = 3;
|
||||
|
||||
height_data->ssdm = subsurf_make_derived_from_derived(
|
||||
|
|
|
@ -127,17 +127,49 @@ static void sequence_invalidate_cache(Scene *scene,
|
|||
SEQ_prefetch_stop(scene);
|
||||
}
|
||||
|
||||
/* Find metastrips that contain invalidated_seq and invalidate them. */
|
||||
static bool seq_relations_find_and_invalidate_metas(Scene *scene,
|
||||
Sequence *invalidated_seq,
|
||||
Sequence *meta_seq)
|
||||
{
|
||||
ListBase *seqbase;
|
||||
|
||||
if (meta_seq == NULL) {
|
||||
Editing *ed = SEQ_editing_get(scene, false);
|
||||
seqbase = &ed->seqbase;
|
||||
}
|
||||
else {
|
||||
seqbase = &meta_seq->seqbase;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (Sequence *, seq, seqbase) {
|
||||
if (seq->type == SEQ_TYPE_META) {
|
||||
if (seq_relations_find_and_invalidate_metas(scene, invalidated_seq, seq)) {
|
||||
sequence_invalidate_cache(scene, seq, true, SEQ_CACHE_ALL_TYPES);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (seq == invalidated_seq && meta_seq != NULL) {
|
||||
sequence_invalidate_cache(scene, meta_seq, true, SEQ_CACHE_ALL_TYPES);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SEQ_relations_invalidate_cache_in_range(Scene *scene,
|
||||
Sequence *seq,
|
||||
Sequence *range_mask,
|
||||
int invalidate_types)
|
||||
{
|
||||
seq_cache_cleanup_sequence(scene, seq, range_mask, invalidate_types, true);
|
||||
seq_relations_find_and_invalidate_metas(scene, seq, NULL);
|
||||
}
|
||||
|
||||
void SEQ_relations_invalidate_cache_raw(Scene *scene, Sequence *seq)
|
||||
{
|
||||
sequence_invalidate_cache(scene, seq, true, SEQ_CACHE_ALL_TYPES);
|
||||
seq_relations_find_and_invalidate_metas(scene, seq, NULL);
|
||||
}
|
||||
|
||||
void SEQ_relations_invalidate_cache_preprocessed(Scene *scene, Sequence *seq)
|
||||
|
@ -147,6 +179,7 @@ void SEQ_relations_invalidate_cache_preprocessed(Scene *scene, Sequence *seq)
|
|||
true,
|
||||
SEQ_CACHE_STORE_PREPROCESSED | SEQ_CACHE_STORE_COMPOSITE |
|
||||
SEQ_CACHE_STORE_FINAL_OUT);
|
||||
seq_relations_find_and_invalidate_metas(scene, seq, NULL);
|
||||
}
|
||||
|
||||
void SEQ_relations_invalidate_cache_composite(Scene *scene, Sequence *seq)
|
||||
|
@ -157,6 +190,7 @@ void SEQ_relations_invalidate_cache_composite(Scene *scene, Sequence *seq)
|
|||
|
||||
sequence_invalidate_cache(
|
||||
scene, seq, true, SEQ_CACHE_STORE_COMPOSITE | SEQ_CACHE_STORE_FINAL_OUT);
|
||||
seq_relations_find_and_invalidate_metas(scene, seq, NULL);
|
||||
}
|
||||
|
||||
void SEQ_relations_invalidate_dependent(Scene *scene, Sequence *seq)
|
||||
|
@ -167,6 +201,7 @@ void SEQ_relations_invalidate_dependent(Scene *scene, Sequence *seq)
|
|||
|
||||
sequence_invalidate_cache(
|
||||
scene, seq, false, SEQ_CACHE_STORE_COMPOSITE | SEQ_CACHE_STORE_FINAL_OUT);
|
||||
seq_relations_find_and_invalidate_metas(scene, seq, NULL);
|
||||
}
|
||||
|
||||
static void invalidate_scene_strips(Scene *scene, Scene *scene_target, ListBase *seqbase)
|
||||
|
|
|
@ -188,7 +188,7 @@ bool WM_stereo3d_enabled(struct wmWindow *win, bool only_fullscreen_test);
|
|||
void WM_file_autoexec_init(const char *filepath);
|
||||
bool WM_file_read(struct bContext *C, const char *filepath, struct ReportList *reports);
|
||||
void WM_autosave_init(struct wmWindowManager *wm);
|
||||
void WM_recover_last_session(struct bContext *C, struct ReportList *reports);
|
||||
bool WM_recover_last_session(struct bContext *C, struct ReportList *reports);
|
||||
void WM_file_tag_modified(void);
|
||||
|
||||
struct ID *WM_file_append_datablock(struct Main *bmain,
|
||||
|
|
|
@ -143,6 +143,8 @@ static void wm_history_file_free(RecentFile *recent);
|
|||
static void wm_history_file_update(void);
|
||||
static void wm_history_file_write(void);
|
||||
|
||||
static void wm_test_autorun_revert_action_exec(bContext *C);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Misc Utility Functions
|
||||
* \{ */
|
||||
|
@ -669,6 +671,9 @@ static void wm_file_read_post(bContext *C,
|
|||
* won't be set to a valid value again */
|
||||
CTX_wm_window_set(C, NULL); /* exits queues */
|
||||
|
||||
/* Ensure auto-run action is not used from a previous blend file load. */
|
||||
wm_test_autorun_revert_action_set(NULL, NULL);
|
||||
|
||||
/* Ensure tools are registered. */
|
||||
WM_toolsystem_init(C);
|
||||
}
|
||||
|
@ -2167,10 +2172,7 @@ void WM_OT_read_factory_settings(wmOperatorType *ot)
|
|||
/**
|
||||
* Wrap #WM_file_read, shared by file reading operators.
|
||||
*/
|
||||
static bool wm_file_read_opwrap(bContext *C,
|
||||
const char *filepath,
|
||||
ReportList *reports,
|
||||
const bool autoexec_init)
|
||||
static bool wm_file_read_opwrap(bContext *C, const char *filepath, ReportList *reports)
|
||||
{
|
||||
bool success;
|
||||
|
||||
|
@ -2178,7 +2180,8 @@ static bool wm_file_read_opwrap(bContext *C,
|
|||
/* do it before for now, but is this correct with multiple windows? */
|
||||
WM_event_add_notifier(C, NC_WINDOW, NULL);
|
||||
|
||||
if (autoexec_init) {
|
||||
/* Set by the "use_scripts" property on file load. */
|
||||
if ((G.f & G_FLAG_SCRIPT_AUTOEXEC) == 0) {
|
||||
WM_file_autoexec_init(filepath);
|
||||
}
|
||||
|
||||
|
@ -2308,21 +2311,9 @@ static int wm_open_mainfile__open(bContext *C, wmOperator *op)
|
|||
wm_open_init_load_ui(op, false);
|
||||
wm_open_init_use_scripts(op, false);
|
||||
|
||||
if (RNA_boolean_get(op->ptr, "load_ui")) {
|
||||
G.fileflags &= ~G_FILE_NO_UI;
|
||||
}
|
||||
else {
|
||||
G.fileflags |= G_FILE_NO_UI;
|
||||
}
|
||||
|
||||
if (RNA_boolean_get(op->ptr, "use_scripts")) {
|
||||
G.f |= G_FLAG_SCRIPT_AUTOEXEC;
|
||||
}
|
||||
else {
|
||||
G.f &= ~G_FLAG_SCRIPT_AUTOEXEC;
|
||||
}
|
||||
|
||||
success = wm_file_read_opwrap(C, filepath, op->reports, !(G.f & G_FLAG_SCRIPT_AUTOEXEC));
|
||||
SET_FLAG_FROM_TEST(G.fileflags, !RNA_boolean_get(op->ptr, "load_ui"), G_FILE_NO_UI);
|
||||
SET_FLAG_FROM_TEST(G.f, RNA_boolean_get(op->ptr, "use_scripts"), G_FLAG_SCRIPT_AUTOEXEC);
|
||||
success = wm_file_read_opwrap(C, filepath, op->reports);
|
||||
|
||||
/* for file open also popup for warnings, not only errors */
|
||||
BKE_report_print_level_set(op->reports, RPT_WARNING);
|
||||
|
@ -2453,6 +2444,16 @@ static void wm_open_mainfile_ui(bContext *UNUSED(C), wmOperator *op)
|
|||
uiItemR(col, op->ptr, "use_scripts", 0, autoexec_text, ICON_NONE);
|
||||
}
|
||||
|
||||
static void wm_open_mainfile_def_property_use_scripts(wmOperatorType *ot)
|
||||
{
|
||||
RNA_def_boolean(ot->srna,
|
||||
"use_scripts",
|
||||
true,
|
||||
"Trusted Source",
|
||||
"Allow .blend file to execute scripts automatically, default available from "
|
||||
"system preferences");
|
||||
}
|
||||
|
||||
void WM_OT_open_mainfile(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Open";
|
||||
|
@ -2476,12 +2477,8 @@ void WM_OT_open_mainfile(wmOperatorType *ot)
|
|||
|
||||
RNA_def_boolean(
|
||||
ot->srna, "load_ui", true, "Load UI", "Load user interface setup in the .blend file");
|
||||
RNA_def_boolean(ot->srna,
|
||||
"use_scripts",
|
||||
true,
|
||||
"Trusted Source",
|
||||
"Allow .blend file to execute scripts automatically, default available from "
|
||||
"system preferences");
|
||||
|
||||
wm_open_mainfile_def_property_use_scripts(ot);
|
||||
|
||||
PropertyRNA *prop = RNA_def_boolean(
|
||||
ot->srna, "display_file_selector", true, "Display File Selector", "");
|
||||
|
@ -2504,15 +2501,10 @@ static int wm_revert_mainfile_exec(bContext *C, wmOperator *op)
|
|||
|
||||
wm_open_init_use_scripts(op, false);
|
||||
|
||||
if (RNA_boolean_get(op->ptr, "use_scripts")) {
|
||||
G.f |= G_FLAG_SCRIPT_AUTOEXEC;
|
||||
}
|
||||
else {
|
||||
G.f &= ~G_FLAG_SCRIPT_AUTOEXEC;
|
||||
}
|
||||
SET_FLAG_FROM_TEST(G.f, RNA_boolean_get(op->ptr, "use_scripts"), G_FLAG_SCRIPT_AUTOEXEC);
|
||||
|
||||
BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath));
|
||||
success = wm_file_read_opwrap(C, filepath, op->reports, !(G.f & G_FLAG_SCRIPT_AUTOEXEC));
|
||||
success = wm_file_read_opwrap(C, filepath, op->reports);
|
||||
|
||||
if (success) {
|
||||
return OPERATOR_FINISHED;
|
||||
|
@ -2535,12 +2527,7 @@ void WM_OT_revert_mainfile(wmOperatorType *ot)
|
|||
ot->exec = wm_revert_mainfile_exec;
|
||||
ot->poll = wm_revert_mainfile_poll;
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"use_scripts",
|
||||
true,
|
||||
"Trusted Source",
|
||||
"Allow .blend file to execute scripts automatically, default available from "
|
||||
"system preferences");
|
||||
wm_open_mainfile_def_property_use_scripts(ot);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -2549,35 +2536,39 @@ void WM_OT_revert_mainfile(wmOperatorType *ot)
|
|||
/** \name Recover Last Session Operator
|
||||
* \{ */
|
||||
|
||||
void WM_recover_last_session(bContext *C, ReportList *reports)
|
||||
bool WM_recover_last_session(bContext *C, ReportList *reports)
|
||||
{
|
||||
char filepath[FILE_MAX];
|
||||
|
||||
BLI_join_dirfile(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE);
|
||||
/* if reports==NULL, it's called directly without operator, we add a quick check here */
|
||||
if (reports || BLI_exists(filepath)) {
|
||||
G.fileflags |= G_FILE_RECOVER;
|
||||
|
||||
wm_file_read_opwrap(C, filepath, reports, true);
|
||||
|
||||
G.fileflags &= ~G_FILE_RECOVER;
|
||||
|
||||
/* XXX bad global... fixme */
|
||||
Main *bmain = CTX_data_main(C);
|
||||
if (BKE_main_blendfile_path(bmain)[0] != '\0') {
|
||||
G.file_loaded = 1; /* prevents splash to show */
|
||||
}
|
||||
else {
|
||||
G.relbase_valid = 0;
|
||||
G.save_over = 0; /* start with save preference untitled.blend */
|
||||
}
|
||||
}
|
||||
G.fileflags |= G_FILE_RECOVER;
|
||||
const bool success = wm_file_read_opwrap(C, filepath, reports);
|
||||
G.fileflags &= ~G_FILE_RECOVER;
|
||||
return success;
|
||||
}
|
||||
|
||||
static int wm_recover_last_session_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
WM_recover_last_session(C, op->reports);
|
||||
return OPERATOR_FINISHED;
|
||||
wm_open_init_use_scripts(op, true);
|
||||
SET_FLAG_FROM_TEST(G.f, RNA_boolean_get(op->ptr, "use_scripts"), G_FLAG_SCRIPT_AUTOEXEC);
|
||||
if (WM_recover_last_session(C, op->reports)) {
|
||||
if (!G.background) {
|
||||
wmOperatorType *ot = op->type;
|
||||
PointerRNA *props_ptr = MEM_callocN(sizeof(PointerRNA), __func__);
|
||||
WM_operator_properties_create_ptr(props_ptr, ot);
|
||||
RNA_boolean_set(props_ptr, "use_scripts", true);
|
||||
wm_test_autorun_revert_action_set(ot, props_ptr);
|
||||
}
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
static int wm_recover_last_session_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
/* Keep the current setting instead of using the preferences since a file selector
|
||||
* doesn't give us the option to change the setting. */
|
||||
wm_open_init_use_scripts(op, false);
|
||||
return WM_operator_confirm(C, op, event);
|
||||
}
|
||||
|
||||
void WM_OT_recover_last_session(wmOperatorType *ot)
|
||||
|
@ -2586,8 +2577,10 @@ void WM_OT_recover_last_session(wmOperatorType *ot)
|
|||
ot->idname = "WM_OT_recover_last_session";
|
||||
ot->description = "Open the last closed file (\"" BLENDER_QUIT_FILE "\")";
|
||||
|
||||
ot->invoke = WM_operator_confirm;
|
||||
ot->invoke = wm_recover_last_session_invoke;
|
||||
ot->exec = wm_recover_last_session_exec;
|
||||
|
||||
wm_open_mainfile_def_property_use_scripts(ot);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -2603,13 +2596,23 @@ static int wm_recover_auto_save_exec(bContext *C, wmOperator *op)
|
|||
|
||||
RNA_string_get(op->ptr, "filepath", filepath);
|
||||
|
||||
wm_open_init_use_scripts(op, true);
|
||||
SET_FLAG_FROM_TEST(G.f, RNA_boolean_get(op->ptr, "use_scripts"), G_FLAG_SCRIPT_AUTOEXEC);
|
||||
|
||||
G.fileflags |= G_FILE_RECOVER;
|
||||
|
||||
success = wm_file_read_opwrap(C, filepath, op->reports, true);
|
||||
success = wm_file_read_opwrap(C, filepath, op->reports);
|
||||
|
||||
G.fileflags &= ~G_FILE_RECOVER;
|
||||
|
||||
if (success) {
|
||||
if (!G.background) {
|
||||
wmOperatorType *ot = op->type;
|
||||
PointerRNA *props_ptr = MEM_callocN(sizeof(PointerRNA), __func__);
|
||||
WM_operator_properties_create_ptr(props_ptr, ot);
|
||||
RNA_boolean_set(props_ptr, "use_scripts", true);
|
||||
wm_test_autorun_revert_action_set(ot, props_ptr);
|
||||
}
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
return OPERATOR_CANCELLED;
|
||||
|
@ -2621,6 +2624,7 @@ static int wm_recover_auto_save_invoke(bContext *C, wmOperator *op, const wmEven
|
|||
|
||||
wm_autosave_location(filename);
|
||||
RNA_string_set(op->ptr, "filepath", filename);
|
||||
wm_open_init_use_scripts(op, true);
|
||||
WM_event_add_fileselect(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
|
@ -2642,6 +2646,8 @@ void WM_OT_recover_auto_save(wmOperatorType *ot)
|
|||
WM_FILESEL_FILEPATH,
|
||||
FILE_VERTICALDISPLAY,
|
||||
FILE_SORT_TIME);
|
||||
|
||||
wm_open_mainfile_def_property_use_scripts(ot);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -2907,6 +2913,9 @@ static void wm_block_autorun_warning_ignore(bContext *C, void *arg_block, void *
|
|||
{
|
||||
wmWindow *win = CTX_wm_window(C);
|
||||
UI_popup_block_close(C, win, arg_block);
|
||||
|
||||
/* Free the data as it's no longer needed. */
|
||||
wm_test_autorun_revert_action_set(NULL, NULL);
|
||||
}
|
||||
|
||||
static void wm_block_autorun_warning_reload_with_scripts(bContext *C,
|
||||
|
@ -2924,13 +2933,7 @@ static void wm_block_autorun_warning_reload_with_scripts(bContext *C,
|
|||
|
||||
/* Load file again with scripts enabled.
|
||||
* The reload is necessary to allow scripts to run when the files loads. */
|
||||
wmOperatorType *ot = WM_operatortype_find("WM_OT_revert_mainfile", false);
|
||||
|
||||
PointerRNA props_ptr;
|
||||
WM_operator_properties_create_ptr(&props_ptr, ot);
|
||||
RNA_boolean_set(&props_ptr, "use_scripts", true);
|
||||
WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &props_ptr);
|
||||
WM_operator_properties_free(&props_ptr);
|
||||
wm_test_autorun_revert_action_exec(C);
|
||||
}
|
||||
|
||||
static void wm_block_autorun_warning_enable_scripts(bContext *C,
|
||||
|
@ -3068,6 +3071,54 @@ static uiBlock *block_create_autorun_warning(struct bContext *C,
|
|||
return block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the action needed if the user needs to reload the file with Python scripts enabled.
|
||||
*
|
||||
* When left to NULL, this is simply revert.
|
||||
* When loading files through the recover auto-save or session,
|
||||
* we need to revert using other operators.
|
||||
*/
|
||||
static struct {
|
||||
wmOperatorType *ot;
|
||||
PointerRNA *ptr;
|
||||
} wm_test_autorun_revert_action_data = {
|
||||
.ot = NULL,
|
||||
.ptr = NULL,
|
||||
};
|
||||
|
||||
void wm_test_autorun_revert_action_set(wmOperatorType *ot, PointerRNA *ptr)
|
||||
{
|
||||
BLI_assert(!G.background);
|
||||
wm_test_autorun_revert_action_data.ot = NULL;
|
||||
if (wm_test_autorun_revert_action_data.ptr != NULL) {
|
||||
WM_operator_properties_free(wm_test_autorun_revert_action_data.ptr);
|
||||
MEM_freeN(wm_test_autorun_revert_action_data.ptr);
|
||||
wm_test_autorun_revert_action_data.ptr = NULL;
|
||||
}
|
||||
wm_test_autorun_revert_action_data.ot = ot;
|
||||
wm_test_autorun_revert_action_data.ptr = ptr;
|
||||
}
|
||||
|
||||
void wm_test_autorun_revert_action_exec(bContext *C)
|
||||
{
|
||||
wmOperatorType *ot = wm_test_autorun_revert_action_data.ot;
|
||||
PointerRNA *ptr = wm_test_autorun_revert_action_data.ptr;
|
||||
|
||||
/* Use regular revert. */
|
||||
if (ot == NULL) {
|
||||
ot = WM_operatortype_find("WM_OT_revert_mainfile", false);
|
||||
ptr = MEM_callocN(sizeof(PointerRNA), __func__);
|
||||
WM_operator_properties_create_ptr(ptr, ot);
|
||||
RNA_boolean_set(ptr, "use_scripts", true);
|
||||
|
||||
/* Set state, so it's freed correctly */
|
||||
wm_test_autorun_revert_action_set(ot, ptr);
|
||||
}
|
||||
|
||||
WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, ptr);
|
||||
wm_test_autorun_revert_action_set(NULL, NULL);
|
||||
}
|
||||
|
||||
void wm_test_autorun_warning(bContext *C)
|
||||
{
|
||||
/* Test if any auto-execution of scripts failed. */
|
||||
|
|
|
@ -517,6 +517,9 @@ void WM_exit_ex(bContext *C, const bool do_python)
|
|||
BKE_blendfile_userdef_write_all(NULL);
|
||||
}
|
||||
}
|
||||
/* Free the callback data used on file-open
|
||||
* (will be set when a recover operation has run). */
|
||||
wm_test_autorun_revert_action_set(NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -86,6 +86,7 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win) ATTR_
|
|||
int wm_window_new_exec(bContext *C, struct wmOperator *op);
|
||||
int wm_window_new_main_exec(bContext *C, struct wmOperator *op);
|
||||
|
||||
void wm_test_autorun_revert_action_set(struct wmOperatorType *ot, struct PointerRNA *ptr);
|
||||
void wm_test_autorun_warning(bContext *C);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -92,7 +92,8 @@ static void wm_xr_draw_viewport_buffers_to_active_framebuffer(
|
|||
if (is_upside_down) {
|
||||
SWAP(int, rect.ymin, rect.ymax);
|
||||
}
|
||||
GPU_viewport_draw_to_screen_ex(surface_data->viewport, 0, &rect, draw_view->expects_srgb_buffer);
|
||||
GPU_viewport_draw_to_screen_ex(
|
||||
surface_data->viewport, 0, &rect, draw_view->expects_srgb_buffer, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue