Merge branch 'master' into sculpt-dev

This commit is contained in:
Pablo Dobarro 2021-01-26 20:30:39 +01:00
commit a72cf784a7
98 changed files with 1775 additions and 908 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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));
}

View File

@ -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;

View File

@ -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(

View File

@ -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)

View File

@ -1594,6 +1594,7 @@ class _defs_texture_paint:
icon_prefix="brush.paint_texture.",
type=bpy.types.Brush,
attr="image_tool",
cursor='PAINT_CROSS',
)

View File

@ -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"),

View File

@ -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

View File

@ -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

View 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);

View File

@ -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;

View File

@ -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
/** \} */

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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.

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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. */

View File

@ -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;

View File

@ -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.
*

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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();

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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. */

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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 */

View File

@ -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,

View File

@ -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;
}

View File

@ -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);
}
}
/** \} */

View File

@ -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,

View File

@ -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;
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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)

View File

@ -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(&region->winrct) + 1;
height = BLI_rcti_size_y(&region->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;
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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(&region->winrct) + 1;
height = BLI_rcti_size_y(&region->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)

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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. */

View File

@ -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, \

View File

@ -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

View File

@ -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[] = {

View File

@ -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)

View File

@ -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},
};

View File

@ -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)

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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:

View File

@ -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)

View File

@ -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]);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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]);
}
}
}

View File

@ -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 &params,
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 &params,
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 &params)
{
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);
}

View File

@ -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);
}
}
}

View File

@ -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(

View File

@ -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)

View File

@ -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,

View File

@ -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. */

View File

@ -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);
}
}

View File

@ -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

View File

@ -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);
}
/**