Merge branch 'master' into sculpt-dev

This commit is contained in:
Pablo Dobarro 2021-05-10 19:01:57 +02:00
commit fad42fc6c7
321 changed files with 10673 additions and 4363 deletions

View File

@ -255,6 +255,7 @@ ForEachMacros:
- SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN
- SEQ_ALL_BEGIN
- SEQ_ITERATOR_FOREACH
- SURFACE_QUAD_ITER_BEGIN
- foreach
- ED_screen_areas_iter

View File

@ -4,7 +4,6 @@ Mesh with Random Vertex Colors
"""
import bpy
import gpu
import bgl
import numpy as np
from random import random
from gpu_extras.batch import batch_for_shader
@ -31,9 +30,10 @@ batch = batch_for_shader(
def draw():
bgl.glEnable(bgl.GL_DEPTH_TEST)
gpu.state.depth_test_set('LESS_EQUAL')
gpu.state.depth_mask_set(True)
batch.draw(shader)
bgl.glDisable(bgl.GL_DEPTH_TEST)
gpu.state.depth_mask_set(False)
bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW')

View File

@ -6,11 +6,11 @@ To use this example you have to provide an image that should be displayed.
"""
import bpy
import gpu
import bgl
from gpu_extras.batch import batch_for_shader
IMAGE_NAME = "Untitled"
image = bpy.data.images[IMAGE_NAME]
texture = gpu.texture.from_image(image)
shader = gpu.shader.from_builtin('2D_IMAGE')
batch = batch_for_shader(
@ -21,16 +21,9 @@ batch = batch_for_shader(
},
)
if image.gl_load():
raise Exception()
def draw():
bgl.glActiveTexture(bgl.GL_TEXTURE0)
bgl.glBindTexture(bgl.GL_TEXTURE_2D, image.bindcode)
shader.bind()
shader.uniform_int("image", 0)
shader.uniform_sampler("image", texture)
batch.draw(shader)

View File

@ -9,7 +9,6 @@ Generate a texture using Offscreen Rendering
"""
import bpy
import gpu
import bgl
from mathutils import Matrix
from gpu_extras.batch import batch_for_shader
from gpu_extras.presets import draw_circle_2d
@ -20,8 +19,8 @@ from gpu_extras.presets import draw_circle_2d
offscreen = gpu.types.GPUOffScreen(512, 512)
with offscreen.bind():
bgl.glClearColor(0.0, 0.0, 0.0, 0.0)
bgl.glClear(bgl.GL_COLOR_BUFFER_BIT)
fb = gpu.state.active_framebuffer_get()
fb.clear(color=(0.0, 0.0, 0.0, 0.0))
with gpu.matrix.push_pop():
# reset matrices -> use normalized device coordinates [-1, 1]
gpu.matrix.load_matrix(Matrix.Identity(4))
@ -75,13 +74,10 @@ batch = batch_for_shader(
def draw():
bgl.glActiveTexture(bgl.GL_TEXTURE0)
bgl.glBindTexture(bgl.GL_TEXTURE_2D, offscreen.color_texture)
shader.bind()
shader.uniform_float("modelMatrix", Matrix.Translation((1, 2, 3)) @ Matrix.Scale(3, 4))
shader.uniform_float("viewProjectionMatrix", bpy.context.region_data.perspective_matrix)
shader.uniform_float("image", 0)
shader.uniform_sampler("image", offscreen.texture_color)
batch.draw(shader)

View File

@ -7,11 +7,10 @@ If it already exists, it will override the existing one.
Currently almost all of the execution time is spent in the last line.
In the future this will hopefully be solved by implementing the Python buffer protocol
for :class:`bgl.Buffer` and :class:`bpy.types.Image.pixels` (aka ``bpy_prop_array``).
for :class:`gpu.types.Buffer` and :class:`bpy.types.Image.pixels` (aka ``bpy_prop_array``).
"""
import bpy
import gpu
import bgl
import random
from mathutils import Matrix
from gpu_extras.presets import draw_circle_2d
@ -25,8 +24,8 @@ RING_AMOUNT = 10
offscreen = gpu.types.GPUOffScreen(WIDTH, HEIGHT)
with offscreen.bind():
bgl.glClearColor(0.0, 0.0, 0.0, 0.0)
bgl.glClear(bgl.GL_COLOR_BUFFER_BIT)
fb = gpu.state.active_framebuffer_get()
fb.clear(color=(0.0, 0.0, 0.0, 0.0))
with gpu.matrix.push_pop():
# reset matrices -> use normalized device coordinates [-1, 1]
gpu.matrix.load_matrix(Matrix.Identity(4))
@ -37,9 +36,7 @@ with offscreen.bind():
(random.uniform(-1, 1), random.uniform(-1, 1)),
(1, 1, 1, 1), random.uniform(0.1, 1), 20)
buffer = bgl.Buffer(bgl.GL_BYTE, WIDTH * HEIGHT * 4)
bgl.glReadBuffer(bgl.GL_BACK)
bgl.glReadPixels(0, 0, WIDTH, HEIGHT, bgl.GL_RGBA, bgl.GL_UNSIGNED_BYTE, buffer)
buffer = fb.read_color(0, 0, WIDTH, HEIGHT, 4, 0, 'UBYTE')
offscreen.free()
@ -48,4 +45,6 @@ if not IMAGE_NAME in bpy.data.images:
bpy.data.images.new(IMAGE_NAME, WIDTH, HEIGHT)
image = bpy.data.images[IMAGE_NAME]
image.scale(WIDTH, HEIGHT)
buffer.dimensions = WIDTH * HEIGHT * 4
image.pixels = [v / 255 for v in buffer]

View File

@ -7,7 +7,6 @@ You could also make this independent of a specific camera,
but Blender does not expose good functions to create view and projection matrices yet.
"""
import bpy
import bgl
import gpu
from gpu_extras.presets import draw_texture_2d
@ -34,8 +33,8 @@ def draw():
view_matrix,
projection_matrix)
bgl.glDisable(bgl.GL_DEPTH_TEST)
draw_texture_2d(offscreen.color_texture, (10, 10), WIDTH, HEIGHT)
gpu.state.depth_mask_set(False)
draw_texture_2d(offscreen.texture_color, (10, 10), WIDTH, HEIGHT)
bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_PIXEL')

View File

@ -1,7 +1,8 @@
/* T76453: Prevent Long enum lists */
.field-list li {
.field-list > dd p {
max-height: 245px;
overflow-y: auto !important;
word-break: break-word;
}
/* Hide home icon in search area */
@ -11,3 +12,15 @@
.wy-nav-content {
max-width: 1000px !important;
}
/* Fix long titles on mobile */
h1, h2, h3, h4, h5, h6 {word-break: break-all}
/* Temp fix for https://github.com/readthedocs/sphinx_rtd_theme/pull/1109 */
.hlist tr {
display: -ms-flexbox;
display: flex;
flex-flow: row wrap;
}
.hlist td {margin-right: auto}

View File

@ -118,6 +118,7 @@ typedef struct CLG_LogType {
typedef struct CLG_LogRef {
const char *identifier;
CLG_LogType *type;
struct CLG_LogRef *next;
} CLG_LogRef;
void CLG_log_str(CLG_LogType *lg,

View File

@ -81,6 +81,8 @@ typedef struct CLG_IDFilter {
typedef struct CLogContext {
/** Single linked list of types. */
CLG_LogType *types;
/** Single linked list of references. */
CLG_LogRef *refs;
#ifdef WITH_CLOG_PTHREADS
pthread_mutex_t types_lock;
#endif
@ -673,6 +675,12 @@ static void CLG_ctx_free(CLogContext *ctx)
MEM_freeN(item);
}
while (ctx->refs != NULL) {
CLG_LogRef *item = ctx->refs;
ctx->refs = item->next;
item->type = NULL;
}
for (uint i = 0; i < 2; i++) {
while (ctx->filters[i] != NULL) {
CLG_IDFilter *item = ctx->filters[i];
@ -769,6 +777,10 @@ void CLG_logref_init(CLG_LogRef *clg_ref)
pthread_mutex_lock(&g_ctx->types_lock);
#endif
if (clg_ref->type == NULL) {
/* Add to the refs list so we can NULL the pointers to 'type' when CLG_exit() is called. */
clg_ref->next = g_ctx->refs;
g_ctx->refs = clg_ref;
CLG_LogType *clg_ty = clg_ctx_type_find_by_name(g_ctx, clg_ref->identifier);
if (clg_ty == NULL) {
clg_ty = clg_ctx_type_register(g_ctx, clg_ref->identifier);

View File

@ -71,6 +71,16 @@ if(WITH_CYCLES_STANDALONE)
target_link_libraries(cycles ${LIBRARIES})
cycles_target_link_libraries(cycles)
if(APPLE)
if(WITH_OPENCOLORIO)
set_property(TARGET cycles APPEND_STRING PROPERTY LINK_FLAGS " -framework IOKit")
endif()
if(WITH_OPENIMAGEDENOISE AND "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64")
# OpenImageDenoise uses BNNS from the Accelerate framework.
set_property(TARGET cycles APPEND_STRING PROPERTY LINK_FLAGS " -framework Accelerate")
endif()
endif()
if(UNIX AND NOT APPLE)
set_target_properties(cycles PROPERTIES INSTALL_RPATH $ORIGIN/lib)
endif()

View File

@ -552,7 +552,9 @@ class CYCLES_RENDER_PT_light_paths_fast_gi(CyclesButtonsPanel, Panel):
if world:
light = world.light_settings
layout.prop(light, "distance", text="AO Distance")
col = layout.column(align=True)
col.prop(light, "ao_factor", text="AO Factor")
col.prop(light, "distance", text="AO Distance")
class CYCLES_RENDER_PT_motion_blur(CyclesButtonsPanel, Panel):

View File

@ -560,10 +560,12 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
if (!cancel && !motion) {
sync_background_light(b_v3d, use_portal);
/* handle removed data and modified pointers */
/* Handle removed data and modified pointers, as this may free memory, delete Nodes in the
* right order to ensure that dependent data is freed after their users. Objects should be
* freed before particle systems and geometries. */
light_map.post_sync();
geometry_map.post_sync();
object_map.post_sync();
geometry_map.post_sync();
particle_system_map.post_sync();
}

View File

@ -35,6 +35,7 @@
#include "util/util_path.h"
#include "util/util_string.h"
#include "util/util_task.h"
#include "util/util_tbb.h"
#include "util/util_types.h"
#ifdef WITH_OSL
@ -288,9 +289,11 @@ static PyObject *render_func(PyObject * /*self*/, PyObject *args)
RNA_pointer_create(NULL, &RNA_Depsgraph, (ID *)PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
BL::Depsgraph b_depsgraph(depsgraphptr);
/* Allow Blender to execute other Python scripts, and isolate TBB tasks so we
* don't get deadlocks with Blender threads accessing shared data like images. */
python_thread_state_save(&session->python_thread_state);
session->render(b_depsgraph);
tbb::this_task_arena::isolate([&] { session->render(b_depsgraph); });
python_thread_state_restore(&session->python_thread_state);
@ -327,7 +330,8 @@ static PyObject *bake_func(PyObject * /*self*/, PyObject *args)
python_thread_state_save(&session->python_thread_state);
session->bake(b_depsgraph, b_object, pass_type, pass_filter, width, height);
tbb::this_task_arena::isolate(
[&] { session->bake(b_depsgraph, b_object, pass_type, pass_filter, width, height); });
python_thread_state_restore(&session->python_thread_state);
@ -373,7 +377,7 @@ static PyObject *reset_func(PyObject * /*self*/, PyObject *args)
python_thread_state_save(&session->python_thread_state);
session->reset_session(b_data, b_depsgraph);
tbb::this_task_arena::isolate([&] { session->reset_session(b_data, b_depsgraph); });
python_thread_state_restore(&session->python_thread_state);
@ -395,7 +399,7 @@ static PyObject *sync_func(PyObject * /*self*/, PyObject *args)
python_thread_state_save(&session->python_thread_state);
session->synchronize(b_depsgraph);
tbb::this_task_arena::isolate([&] { session->synchronize(b_depsgraph); });
python_thread_state_restore(&session->python_thread_state);

View File

@ -237,6 +237,9 @@ void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsg
sync->sync_recalc(b_depsgraph, b_v3d);
}
BL::Object b_camera_override(b_engine.camera_override());
sync->sync_camera(b_render, b_camera_override, width, height, "");
BL::SpaceView3D b_null_space_view3d(PointerRNA_NULL);
BL::RegionView3D b_null_region_view3d(PointerRNA_NULL);
BufferParams buffer_params = BlenderSync::get_buffer_params(b_render,

View File

@ -367,9 +367,17 @@ void Node::copy_value(const SocketType &socket, const Node &other, const SocketT
case SocketType::TRANSFORM_ARRAY:
copy_array<Transform>(this, socket, &other, other_socket);
break;
case SocketType::NODE_ARRAY:
case SocketType::NODE_ARRAY: {
copy_array<void *>(this, socket, &other, other_socket);
array<Node *> &node_array = get_socket_value<array<Node *>>(this, socket);
for (Node *node : node_array) {
node->reference();
}
break;
}
default:
assert(0);
break;
@ -379,6 +387,14 @@ void Node::copy_value(const SocketType &socket, const Node &other, const SocketT
const void *src = ((char *)&other) + other_socket.struct_offset;
void *dst = ((char *)this) + socket.struct_offset;
memcpy(dst, src, socket.size());
if (socket.type == SocketType::NODE) {
Node *node = get_socket_value<Node *>(this, socket);
if (node) {
node->reference();
}
}
}
}
@ -773,6 +789,26 @@ void Node::set_owner(const NodeOwner *owner_)
owner = owner_;
}
void Node::dereference_all_used_nodes()
{
foreach (const SocketType &socket, type->inputs) {
if (socket.type == SocketType::NODE) {
Node *node = get_socket_value<Node *>(this, socket);
if (node) {
node->dereference();
}
}
else if (socket.type == SocketType::NODE_ARRAY) {
const array<Node *> &nodes = get_socket_value<array<Node *>>(this, socket);
for (Node *node : nodes) {
node->dereference();
}
}
}
}
bool Node::socket_is_modified(const SocketType &input) const
{
return (socket_modified & input.modified_flag_bit) != 0;
@ -803,6 +839,25 @@ template<typename T> void Node::set_if_different(const SocketType &input, T valu
socket_modified |= input.modified_flag_bit;
}
void Node::set_if_different(const SocketType &input, Node *value)
{
if (get_socket_value<Node *>(this, input) == value) {
return;
}
Node *old_node = get_socket_value<Node *>(this, input);
if (old_node) {
old_node->dereference();
}
if (value) {
value->reference();
}
get_socket_value<Node *>(this, input) = value;
socket_modified |= input.modified_flag_bit;
}
template<typename T> void Node::set_if_different(const SocketType &input, array<T> &value)
{
if (!socket_is_modified(input)) {
@ -815,6 +870,27 @@ template<typename T> void Node::set_if_different(const SocketType &input, array<
socket_modified |= input.modified_flag_bit;
}
void Node::set_if_different(const SocketType &input, array<Node *> &value)
{
if (!socket_is_modified(input)) {
if (get_socket_value<array<Node *>>(this, input) == value) {
return;
}
}
array<Node *> &old_nodes = get_socket_value<array<Node *>>(this, input);
for (Node *old_node : old_nodes) {
old_node->dereference();
}
for (Node *new_node : value) {
new_node->reference();
}
get_socket_value<array<Node *>>(this, input).steal_data(value);
socket_modified |= input.modified_flag_bit;
}
void Node::print_modified_sockets() const
{
printf("Node : %s\n", name.c_str());

View File

@ -177,8 +177,32 @@ struct Node {
const NodeOwner *get_owner() const;
void set_owner(const NodeOwner *owner_);
int reference_count() const
{
return ref_count;
}
void reference()
{
ref_count += 1;
}
void dereference()
{
ref_count -= 1;
}
/* Set the reference count to zero. This should only be called when we know for sure that the
* Node is not used by anyone else. For now, this is only the case when "deleting" shaders, as
* they are never actually deleted. */
void clear_reference_count()
{
ref_count = 0;
}
protected:
const NodeOwner *owner;
int ref_count{0};
template<typename T> static T &get_socket_value(const Node *node, const SocketType &socket)
{
@ -189,7 +213,19 @@ struct Node {
template<typename T> void set_if_different(const SocketType &input, T value);
/* Explicit overload for Node sockets so we can handle reference counting. The old Node is
* dereferenced, and the new one is referenced. */
void set_if_different(const SocketType &input, Node *value);
template<typename T> void set_if_different(const SocketType &input, array<T> &value);
/* Explicit overload for Node sockets so we can handle reference counting. The old Nodes are
* dereferenced, and the new ones are referenced. */
void set_if_different(const SocketType &input, array<Node *> &value);
/* Call this function in derived classes' destructors to ensure that used Nodes are dereferenced
* properly. */
void dereference_all_used_nodes();
};
CCL_NAMESPACE_END

View File

@ -148,16 +148,17 @@ struct NodeType {
#define NODE_DECLARE \
static const NodeType *get_node_type(); \
template<typename T> static const NodeType *register_type(); \
static Node *create(const NodeType *type);
static Node *create(const NodeType *type); \
static const NodeType *node_type;
#define NODE_DEFINE(structname) \
const NodeType *structname::node_type = structname::register_type<structname>(); \
Node *structname::create(const NodeType *) \
{ \
return new structname(); \
} \
const NodeType *structname::get_node_type() \
{ \
static const NodeType *node_type = register_type<structname>(); \
return node_type; \
} \
template<typename T> const NodeType *structname::register_type()
@ -169,6 +170,8 @@ struct NodeType {
#define NODE_ABSTRACT_DEFINE(structname) \
const NodeType *structname::get_node_base_type() \
{ \
/* Base types constructed in this getter to ensure correct initialization \
* order. Regular types are not so they are auto-registered for XML parsing. */ \
static const NodeType *node_base_type = register_base_type<structname>(); \
return node_base_type; \
} \

View File

@ -200,12 +200,12 @@ ccl_device bool light_spread_clamp_area_light(const float3 P,
* uv coordinates. */
const float new_center_u = 0.5f * (min_u + max_u);
const float new_center_v = 0.5f * (min_v + max_v);
const float new_len_u = 0.5f * (max_u - min_u);
const float new_len_v = 0.5f * (max_v - min_v);
const float new_len_u = max_u - min_u;
const float new_len_v = max_v - min_v;
*lightP = *lightP + new_center_u * u + new_center_v * v;
*axisu = u * new_len_u * 2.0f;
*axisv = v * new_len_v * 2.0f;
*axisu = u * new_len_u;
*axisv = v * new_len_v;
return true;
}

View File

@ -606,10 +606,10 @@ ccl_device_noinline
t = ray->t;
}
else if (bounce == 0) {
/* Restore original position if nothing was hit after the first bounce.
* Otherwise if the ray_offset() to avoid self-intersection is relatively
* large compared to the scattering radius, we go never backup high enough
* to exit the surface. */
/* Restore original position if nothing was hit after the first bounce,
* without the ray_offset() that was added to avoid self-intersection.
* Otherwise if that offset is relatively large compared to the scattering
* radius, we never go back up high enough to exit the surface. */
ray->P = sd->P;
}

View File

@ -24,6 +24,7 @@ set(INC_SYS
set(SRC
alembic.cpp
alembic_read.cpp
attribute.cpp
background.cpp
bake.cpp
@ -67,6 +68,7 @@ set(SRC
set(SRC_HEADERS
alembic.h
alembic_read.h
attribute.h
bake.h
background.h

File diff suppressed because it is too large Load Diff

View File

@ -152,6 +152,10 @@ template<typename T> class DataStore {
double last_loaded_time = std::numeric_limits<double>::max();
public:
/* Keys used to compare values. */
Alembic::AbcCoreAbstract::ArraySample::Key key1;
Alembic::AbcCoreAbstract::ArraySample::Key key2;
void set_time_sampling(Alembic::AbcCoreAbstract::TimeSampling time_sampling_)
{
time_sampling = time_sampling_;
@ -225,6 +229,11 @@ template<typename T> class DataStore {
index_data_map.push_back({time, data_index.source_time, data_index.index});
}
void add_no_data(double time)
{
index_data_map.push_back({time, time, -1ul});
}
bool is_constant() const
{
return data.size() <= 1;
@ -284,7 +293,7 @@ struct CachedData {
DataStore<array<int3>> triangles{};
/* triangle "loops" are the polygons' vertices indices used for indexing face varying attributes
* (like UVs) */
DataStore<array<int3>> triangles_loops{};
DataStore<array<int>> uv_loops{};
DataStore<array<int>> shader{};
/* subd data */
@ -362,16 +371,18 @@ class AlembicObject : public Node {
void set_object(Object *object);
Object *get_object();
void load_all_data(AlembicProcedural *proc,
Alembic::AbcGeom::IPolyMeshSchema &schema,
Progress &progress);
void load_all_data(AlembicProcedural *proc,
Alembic::AbcGeom::ISubDSchema &schema,
Progress &progress);
void load_all_data(AlembicProcedural *proc,
const Alembic::AbcGeom::ICurvesSchema &schema,
Progress &progress,
float default_radius);
void load_data_in_cache(CachedData &cached_data,
AlembicProcedural *proc,
Alembic::AbcGeom::IPolyMeshSchema &schema,
Progress &progress);
void load_data_in_cache(CachedData &cached_data,
AlembicProcedural *proc,
Alembic::AbcGeom::ISubDSchema &schema,
Progress &progress);
void load_data_in_cache(CachedData &cached_data,
AlembicProcedural *proc,
const Alembic::AbcGeom::ICurvesSchema &schema,
Progress &progress);
bool has_data_loaded() const;
@ -397,33 +408,21 @@ class AlembicObject : public Node {
CachedData &get_cached_data()
{
return cached_data;
return cached_data_;
}
bool is_constant() const
{
return cached_data.is_constant();
return cached_data_.is_constant();
}
Object *object = nullptr;
bool data_loaded = false;
CachedData cached_data;
CachedData cached_data_;
void update_shader_attributes(const Alembic::AbcGeom::ICompoundProperty &arb_geom_params,
Progress &progress);
void read_attribute(const Alembic::AbcGeom::ICompoundProperty &arb_geom_params,
const ustring &attr_name,
Progress &progress);
template<typename SchemaType>
void read_face_sets(SchemaType &schema,
array<int> &polygon_to_shader,
Alembic::AbcGeom::ISampleSelector sample_sel);
void setup_transform_cache(float scale);
void setup_transform_cache(CachedData &cached_data, float scale);
AttributeRequestSet get_requested_attributes();
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,134 @@
/*
* Copyright 2021 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#ifdef WITH_ALEMBIC
# include <Alembic/AbcCoreFactory/All.h>
# include <Alembic/AbcGeom/All.h>
# include "util/util_vector.h"
CCL_NAMESPACE_BEGIN
class AlembicProcedural;
class AttributeRequestSet;
class Progress;
struct CachedData;
/* Maps a FaceSet whose name matches that of a Shader to the index of said shader in the Geometry's
* used_shaders list. */
struct FaceSetShaderIndexPair {
Alembic::AbcGeom::IFaceSet face_set;
int shader_index;
};
/* Data of an IPolyMeshSchema that we need to read. */
struct PolyMeshSchemaData {
Alembic::AbcGeom::TimeSamplingPtr time_sampling;
size_t num_samples;
Alembic::AbcGeom::MeshTopologyVariance topology_variance;
Alembic::AbcGeom::IP3fArrayProperty positions;
Alembic::AbcGeom::IInt32ArrayProperty face_indices;
Alembic::AbcGeom::IInt32ArrayProperty face_counts;
Alembic::AbcGeom::IN3fGeomParam normals;
vector<FaceSetShaderIndexPair> shader_face_sets;
// Unsupported for now.
Alembic::AbcGeom::IV3fArrayProperty velocities;
};
void read_geometry_data(AlembicProcedural *proc,
CachedData &cached_data,
const PolyMeshSchemaData &data,
Progress &progress);
/* Data of an ISubDSchema that we need to read. */
struct SubDSchemaData {
Alembic::AbcGeom::TimeSamplingPtr time_sampling;
size_t num_samples;
Alembic::AbcGeom::MeshTopologyVariance topology_variance;
Alembic::AbcGeom::IInt32ArrayProperty face_counts;
Alembic::AbcGeom::IInt32ArrayProperty face_indices;
Alembic::AbcGeom::IP3fArrayProperty positions;
Alembic::AbcGeom::IInt32ArrayProperty crease_indices;
Alembic::AbcGeom::IInt32ArrayProperty crease_lengths;
Alembic::AbcGeom::IFloatArrayProperty crease_sharpnesses;
vector<FaceSetShaderIndexPair> shader_face_sets;
// Those are unsupported for now.
Alembic::AbcGeom::IInt32ArrayProperty corner_indices;
Alembic::AbcGeom::IFloatArrayProperty corner_sharpnesses;
Alembic::AbcGeom::IInt32Property face_varying_interpolate_boundary;
Alembic::AbcGeom::IInt32Property face_varying_propagate_corners;
Alembic::AbcGeom::IInt32Property interpolate_boundary;
Alembic::AbcGeom::IInt32ArrayProperty holes;
Alembic::AbcGeom::IStringProperty subdivision_scheme;
Alembic::AbcGeom::IV3fArrayProperty velocities;
};
void read_geometry_data(AlembicProcedural *proc,
CachedData &cached_data,
const SubDSchemaData &data,
Progress &progress);
/* Data of a ICurvesSchema that we need to read. */
struct CurvesSchemaData {
Alembic::AbcGeom::TimeSamplingPtr time_sampling;
size_t num_samples;
Alembic::AbcGeom::MeshTopologyVariance topology_variance;
Alembic::AbcGeom::IP3fArrayProperty positions;
Alembic::AbcGeom::IInt32ArrayProperty num_vertices;
float default_radius;
float radius_scale;
// Those are unsupported for now.
Alembic::AbcGeom::IV3fArrayProperty velocities;
// if this property is invalid then the weight for every point is 1
Alembic::AbcGeom::IFloatArrayProperty position_weights;
Alembic::AbcGeom::IN3fGeomParam normals;
Alembic::AbcGeom::IFloatGeomParam widths;
Alembic::AbcGeom::IUcharArrayProperty orders;
Alembic::AbcGeom::IFloatArrayProperty knots;
// TODO(@kevindietrich): type, basis, wrap
};
void read_geometry_data(AlembicProcedural *proc,
CachedData &cached_data,
const CurvesSchemaData &data,
Progress &progress);
void read_attributes(AlembicProcedural *proc,
CachedData &cache,
const Alembic::AbcGeom::ICompoundProperty &arb_geom_params,
const Alembic::AbcGeom::IV2fGeomParam &default_uvs_param,
const AttributeRequestSet &requested_attributes,
Progress &progress);
CCL_NAMESPACE_END
#endif

View File

@ -689,6 +689,9 @@ void AttributeSet::update(AttributeSet &&new_attributes)
it++;
}
/* If all attributes were replaced, transform is no longer applied. */
geometry->transform_applied = false;
}
void AttributeSet::clear_modified()

View File

@ -59,6 +59,7 @@ Background::Background() : Node(get_node_type())
Background::~Background()
{
dereference_all_used_nodes();
}
void Background::device_update(Device *device, DeviceScene *dscene, Scene *scene)

View File

@ -79,6 +79,7 @@ Geometry::Geometry(const NodeType *node_type, const Type type)
Geometry::~Geometry()
{
dereference_all_used_nodes();
delete bvh;
}

View File

@ -159,6 +159,7 @@ NODE_DEFINE(Light)
Light::Light() : Node(get_node_type())
{
dereference_all_used_nodes();
}
void Light::tag_update(Scene *scene)
@ -864,7 +865,7 @@ void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *sc
const float min_spread_angle = 1.0f * M_PI_F / 180.0f;
const float spread_angle = 0.5f * (M_PI_F - max(light->spread, min_spread_angle));
/* Normalization computed using:
* integrate cos(x) (1 - tan(x) * tan(a)) * sin(x) from x = a to pi/2. */
* integrate cos(x) * (1 - tan(x) * tan(a)) * sin(x) from x = 0 to pi/2 - a. */
const float tan_spread = tanf(spread_angle);
const float normalize_spread = 2.0f / (2.0f + (2.0f * spread_angle - M_PI_F) * tan_spread);

View File

@ -1600,11 +1600,23 @@ class SetNormalNode : public ShaderNode {
NODE_SOCKET_API(float3, direction)
};
class OSLNode : public ShaderNode {
class OSLNode final : public ShaderNode {
public:
static OSLNode *create(ShaderGraph *graph, size_t num_inputs, const OSLNode *from = NULL);
~OSLNode();
static void operator delete(void *ptr)
{
/* Override delete operator to silence new-delete-type-mismatch ASAN warnings
* regarding size mismatch in the destructor. This is intentional as we allocate
* extra space at the end of the node. */
::operator delete(ptr);
}
static void operator delete(void *, void *)
{
/* Deliberately empty placement delete operator, to avoid MSVC warning C4291. */
}
ShaderNode *clone(ShaderGraph *graph) const;
char *input_default_value();

View File

@ -91,10 +91,10 @@ void OSLShaderManager::reset(Scene * /*scene*/)
shading_system_init();
}
void OSLShaderManager::device_update(Device *device,
DeviceScene *dscene,
Scene *scene,
Progress &progress)
void OSLShaderManager::device_update_specific(Device *device,
DeviceScene *dscene,
Scene *scene,
Progress &progress)
{
if (!need_update())
return;
@ -1149,7 +1149,7 @@ void OSLCompiler::compile(OSLGlobals *og, Shader *shader)
shader->has_integrator_dependency = false;
/* generate surface shader */
if (shader->used && graph && output->input("Surface")->link) {
if (shader->reference_count() && graph && output->input("Surface")->link) {
shader->osl_surface_ref = compile_type(shader, shader->graph, SHADER_TYPE_SURFACE);
if (has_bump)
@ -1165,7 +1165,7 @@ void OSLCompiler::compile(OSLGlobals *og, Shader *shader)
}
/* generate volume shader */
if (shader->used && graph && output->input("Volume")->link) {
if (shader->reference_count() && graph && output->input("Volume")->link) {
shader->osl_volume_ref = compile_type(shader, shader->graph, SHADER_TYPE_VOLUME);
shader->has_volume = true;
}
@ -1173,7 +1173,7 @@ void OSLCompiler::compile(OSLGlobals *og, Shader *shader)
shader->osl_volume_ref = OSL::ShaderGroupRef();
/* generate displacement shader */
if (shader->used && graph && output->input("Displacement")->link) {
if (shader->reference_count() && graph && output->input("Displacement")->link) {
shader->osl_displacement_ref = compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT);
shader->has_displacement = true;
}

View File

@ -79,7 +79,10 @@ class OSLShaderManager : public ShaderManager {
return true;
}
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
void device_update_specific(Device *device,
DeviceScene *dscene,
Scene *scene,
Progress &progress) override;
void device_free(Device *device, DeviceScene *dscene, Scene *scene);
/* osl compile and query */

View File

@ -143,21 +143,27 @@ void Scene::free_memory(bool final)
delete bvh;
bvh = NULL;
foreach (Shader *s, shaders)
delete s;
/* delete procedurals before other types as they may hold pointers to those types */
/* The order of deletion is important to make sure data is freed based on possible dependencies
* as the Nodes' reference counts are decremented in the destructors:
*
* - Procedurals can create and hold pointers to any other types.
* - Objects can hold pointers to Geometries and ParticleSystems
* - Lights and Geometries can hold pointers to Shaders.
*
* Similarly, we first delete all nodes and their associated device data, and then the managers
* and their associated device data.
*/
foreach (Procedural *p, procedurals)
delete p;
foreach (Geometry *g, geometry)
delete g;
foreach (Object *o, objects)
delete o;
foreach (Light *l, lights)
delete l;
foreach (Geometry *g, geometry)
delete g;
foreach (ParticleSystem *p, particle_systems)
delete p;
foreach (Light *l, lights)
delete l;
shaders.clear();
geometry.clear();
objects.clear();
lights.clear();
@ -169,7 +175,25 @@ void Scene::free_memory(bool final)
film->device_free(device, &dscene, this);
background->device_free(device, &dscene);
integrator->device_free(device, &dscene, true);
}
if (final) {
delete camera;
delete dicing_camera;
delete film;
delete background;
delete integrator;
}
/* Delete Shaders after every other nodes to ensure that we do not try to decrement the reference
* count on some dangling pointer. */
foreach (Shader *s, shaders)
delete s;
shaders.clear();
/* Now that all nodes have been deleted, we can safely delete managers and device data. */
if (device) {
object_manager->device_free(device, &dscene, true);
geometry_manager->device_free(device, &dscene, true);
shader_manager->device_free(device, &dscene, this);
@ -189,11 +213,6 @@ void Scene::free_memory(bool final)
if (final) {
delete lookup_tables;
delete camera;
delete dicing_camera;
delete film;
delete background;
delete integrator;
delete object_manager;
delete geometry_manager;
delete shader_manager;
@ -504,9 +523,6 @@ bool Scene::update(Progress &progress, bool &kernel_switch_needed)
{
/* update scene */
if (need_update()) {
/* Updated used shader tag so we know which features are need for the kernel. */
shader_manager->update_shaders_used(this);
/* Update max_closures. */
KernelIntegrator *kintegrator = &dscene.data.integrator;
if (params.background) {
@ -566,9 +582,6 @@ bool Scene::load_kernels(Progress &progress, bool lock_scene)
return false;
}
progress.add_skip_time(timer, false);
VLOG(1) << "Total time spent loading kernels: " << time_dt() - timer.get_start();
kernels_loaded = true;
loaded_kernel_features = requested_features;
return true;
@ -587,7 +600,7 @@ int Scene::get_max_closure_count()
int max_closures = 0;
for (int i = 0; i < shaders.size(); i++) {
Shader *shader = shaders[i];
if (shader->used) {
if (shader->reference_count()) {
int num_closures = shader->graph->get_num_closures();
max_closures = max(max_closures, num_closures);
}
@ -748,9 +761,10 @@ template<> void Scene::delete_node_impl(ParticleSystem *node)
particle_system_manager->tag_update(this);
}
template<> void Scene::delete_node_impl(Shader * /*node*/)
template<> void Scene::delete_node_impl(Shader *shader)
{
/* don't delete unused shaders, not supported */
shader->clear_reference_count();
}
template<> void Scene::delete_node_impl(Procedural *node)
@ -817,9 +831,12 @@ template<> void Scene::delete_nodes(const set<ParticleSystem *> &nodes, const No
particle_system_manager->tag_update(this);
}
template<> void Scene::delete_nodes(const set<Shader *> & /*nodes*/, const NodeOwner * /*owner*/)
template<> void Scene::delete_nodes(const set<Shader *> &nodes, const NodeOwner * /*owner*/)
{
/* don't delete unused shaders, not supported */
for (Shader *shader : nodes) {
shader->clear_reference_count();
}
}
template<> void Scene::delete_nodes(const set<Procedural *> &nodes, const NodeOwner *owner)

View File

@ -16,7 +16,6 @@
#include "device/device.h"
#include "render/alembic.h"
#include "render/background.h"
#include "render/camera.h"
#include "render/colorspace.h"
@ -27,6 +26,7 @@
#include "render/nodes.h"
#include "render/object.h"
#include "render/osl.h"
#include "render/procedural.h"
#include "render/scene.h"
#include "render/shader.h"
#include "render/svm.h"
@ -218,7 +218,6 @@ Shader::Shader() : Node(get_node_type())
displacement_method = DISPLACE_BUMP;
id = -1;
used = false;
need_update_uvs = true;
need_update_attribute = true;
@ -382,8 +381,9 @@ void Shader::tag_used(Scene *scene)
{
/* if an unused shader suddenly gets used somewhere, it needs to be
* recompiled because it was skipped for compilation before */
if (!used) {
if (!reference_count()) {
tag_modified();
/* We do not reference here as the shader will be referenced when added to a socket. */
scene->shader_manager->tag_update(scene, ShaderManager::SHADER_MODIFIED);
}
}
@ -461,52 +461,28 @@ int ShaderManager::get_shader_id(Shader *shader, bool smooth)
return id;
}
void ShaderManager::update_shaders_used(Scene *scene)
void ShaderManager::device_update(Device *device,
DeviceScene *dscene,
Scene *scene,
Progress &progress)
{
if (!need_update()) {
return;
}
/* figure out which shaders are in use, so SVM/OSL can skip compiling them
* for speed and avoid loading image textures into memory */
uint id = 0;
foreach (Shader *shader, scene->shaders) {
shader->used = false;
shader->id = id++;
}
scene->default_surface->used = true;
scene->default_light->used = true;
scene->default_background->used = true;
scene->default_empty->used = true;
/* Those shaders should always be compiled as they are used as fallback if a shader cannot be
* found, e.g. bad shader index for the triangle shaders on a Mesh. */
assert(scene->default_surface->reference_count() != 0);
assert(scene->default_light->reference_count() != 0);
assert(scene->default_background->reference_count() != 0);
assert(scene->default_empty->reference_count() != 0);
if (scene->background->get_shader())
scene->background->get_shader()->used = true;
#ifdef WITH_ALEMBIC
foreach (Procedural *procedural, scene->procedurals) {
AlembicProcedural *abc_proc = static_cast<AlembicProcedural *>(procedural);
foreach (Node *abc_node, abc_proc->get_objects()) {
AlembicObject *abc_object = static_cast<AlembicObject *>(abc_node);
foreach (Node *node, abc_object->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(node);
shader->used = true;
}
}
}
#endif
foreach (Geometry *geom, scene->geometry)
foreach (Node *node, geom->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(node);
shader->used = true;
}
foreach (Light *light, scene->lights)
if (light->get_shader())
const_cast<Shader *>(light->get_shader())->used = true;
device_update_specific(device, dscene, scene, progress);
}
void ShaderManager::device_update_common(Device *device,
@ -639,6 +615,7 @@ void ShaderManager::add_default(Scene *scene)
Shader *shader = scene->create_node<Shader>();
shader->name = "default_surface";
shader->set_graph(graph);
shader->reference();
scene->default_surface = shader;
shader->tag_update(scene);
}
@ -657,6 +634,8 @@ void ShaderManager::add_default(Scene *scene)
shader->set_graph(graph);
scene->default_volume = shader;
shader->tag_update(scene);
/* No default reference for the volume to avoid compiling volume kernels if there are no actual
* volumes in the scene */
}
/* default light */
@ -673,6 +652,7 @@ void ShaderManager::add_default(Scene *scene)
Shader *shader = scene->create_node<Shader>();
shader->name = "default_light";
shader->set_graph(graph);
shader->reference();
scene->default_light = shader;
shader->tag_update(scene);
}
@ -684,6 +664,7 @@ void ShaderManager::add_default(Scene *scene)
Shader *shader = scene->create_node<Shader>();
shader->name = "default_background";
shader->set_graph(graph);
shader->reference();
scene->default_background = shader;
shader->tag_update(scene);
}
@ -695,6 +676,7 @@ void ShaderManager::add_default(Scene *scene)
Shader *shader = scene->create_node<Shader>();
shader->name = "default_empty";
shader->set_graph(graph);
shader->reference();
scene->default_empty = shader;
shader->tag_update(scene);
}
@ -735,7 +717,7 @@ void ShaderManager::get_requested_features(Scene *scene,
requested_features->nodes_features = 0;
for (int i = 0; i < scene->shaders.size(); i++) {
Shader *shader = scene->shaders[i];
if (!shader->used) {
if (!shader->reference_count()) {
continue;
}

View File

@ -132,7 +132,6 @@ class Shader : public Node {
/* determined before compiling */
uint id;
bool used;
#ifdef WITH_OSL
/* osl shading state references */
@ -187,10 +186,11 @@ class ShaderManager {
}
/* device update */
virtual void device_update(Device *device,
DeviceScene *dscene,
Scene *scene,
Progress &progress) = 0;
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
virtual void device_update_specific(Device *device,
DeviceScene *dscene,
Scene *scene,
Progress &progress) = 0;
virtual void device_free(Device *device, DeviceScene *dscene, Scene *scene) = 0;
void device_update_common(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
@ -208,7 +208,6 @@ class ShaderManager {
static void add_default(Scene *scene);
/* Selective nodes compilation. */
void update_shaders_used(Scene *scene);
void get_requested_features(Scene *scene, DeviceRequestedFeatures *requested_features);
static void free_memory();

View File

@ -69,10 +69,10 @@ void SVMShaderManager::device_update_shader(Scene *scene,
<< summary.full_report();
}
void SVMShaderManager::device_update(Device *device,
DeviceScene *dscene,
Scene *scene,
Progress &progress)
void SVMShaderManager::device_update_specific(Device *device,
DeviceScene *dscene,
Scene *scene,
Progress &progress)
{
if (!need_update())
return;
@ -776,7 +776,7 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
add_node(NODE_ENTER_BUMP_EVAL, bump_state_offset);
}
if (shader->used) {
if (shader->reference_count()) {
CompilerState state(graph);
if (clin->link) {
bool generate = false;

View File

@ -46,7 +46,10 @@ class SVMShaderManager : public ShaderManager {
void reset(Scene *scene);
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
void device_update_specific(Device *device,
DeviceScene *dscene,
Scene *scene,
Progress &progress) override;
void device_free(Device *device, DeviceScene *dscene, Scene *scene);
protected:

View File

@ -362,7 +362,7 @@ ccl_device float fast_atan2f(float y, float x)
ccl_device float fast_log2f(float x)
{
/* NOTE: clamp to avoid special cases and make result "safe" from large
* negative values/nans. */
* negative values/NAN's. */
x = clamp(x, FLT_MIN, FLT_MAX);
unsigned bits = __float_as_uint(x);
int exponent = (int)(bits >> 23) - 127;

View File

@ -145,7 +145,8 @@ int system_cpu_num_active_group_processors()
return numaAPI_GetNumCurrentNodesProcessors();
}
#if !defined(_WIN32) || defined(FREE_WINDOWS)
/* Equivalent of Windows __cpuid for x86 processors on other platforms. */
#if (!defined(_WIN32) || defined(FREE_WINDOWS)) && (defined(__x86_64__) || defined(__i386__))
static void __cpuid(int data[4], int selector)
{
# if defined(__x86_64__)
@ -166,7 +167,34 @@ static void __cpuid(int data[4], int selector)
string system_cpu_brand_string()
{
#if !defined(WIN32) && !defined(__x86_64__) && !defined(__i386__)
#if defined(__APPLE__)
/* Get from system on macOS. */
char modelname[512] = "";
size_t bufferlen = 512;
if (sysctlbyname("machdep.cpu.brand_string", &modelname, &bufferlen, NULL, 0) == 0) {
return modelname;
}
#elif defined(WIN32) || defined(__x86_64__) || defined(__i386__)
/* Get from intrinsics on Windows and x86. */
char buf[49] = {0};
int result[4] = {0};
__cpuid(result, 0x80000000);
if (result[0] != 0 && result[0] >= (int)0x80000004) {
__cpuid((int *)(buf + 0), 0x80000002);
__cpuid((int *)(buf + 16), 0x80000003);
__cpuid((int *)(buf + 32), 0x80000004);
string brand = buf;
/* Make it a bit more presentable. */
brand = string_remove_trademark(brand);
return brand;
}
#else
/* Get from /proc/cpuinfo on Unix systems. */
FILE *cpuinfo = fopen("/proc/cpuinfo", "r");
if (cpuinfo != nullptr) {
char cpuinfo_buf[513] = "";
@ -186,24 +214,6 @@ string system_cpu_brand_string()
}
}
}
#else
char buf[49] = {0};
int result[4] = {0};
__cpuid(result, 0x80000000);
if (result[0] != 0 && result[0] >= (int)0x80000004) {
__cpuid((int *)(buf + 0), 0x80000002);
__cpuid((int *)(buf + 16), 0x80000003);
__cpuid((int *)(buf + 32), 0x80000004);
string brand = buf;
/* make it a bit more presentable */
brand = string_remove_trademark(brand);
return brand;
}
#endif
return "Unknown CPU";
}
@ -213,7 +223,7 @@ int system_cpu_bits()
return (sizeof(void *) * 8);
}
#if defined(__x86_64__) || defined(_M_X64) || defined(i386) || defined(_M_IX86)
#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86)
struct CPUCapabilities {
bool x64;

View File

@ -22,10 +22,17 @@
#include <libavformat/avformat.h>
/* check our ffmpeg is new enough, avoids user complaints */
#if (LIBAVFORMAT_VERSION_MAJOR < 52) || \
((LIBAVFORMAT_VERSION_MAJOR == 52) && (LIBAVFORMAT_VERSION_MINOR <= 64))
# error "FFmpeg 0.7 or newer is needed, Upgrade your FFmpeg or disable it"
/* Check if our ffmpeg is new enough, avoids user complaints.
* Minimum supported version is currently 3.2.0 which mean the following library versions:
* libavutil > 55.30
* libavcodec > 57.60
* libavformat > 57.50
*
* We only check for one of these as they are usually updated in tandem.
*/
#if (LIBAVFORMAT_VERSION_MAJOR < 57) || \
((LIBAVFORMAT_VERSION_MAJOR == 57) && (LIBAVFORMAT_VERSION_MINOR <= 50))
# error "FFmpeg 3.2.0 or newer is needed, Upgrade your FFmpeg or disable it"
#endif
/* end sanity check */
@ -36,274 +43,6 @@
# define FFMPEG_INLINE static inline
#endif
#include <libavcodec/avcodec.h>
#include <libavutil/mathematics.h>
#include <libavutil/opt.h>
#include <libavutil/rational.h>
#if (LIBAVFORMAT_VERSION_MAJOR > 52) || \
((LIBAVFORMAT_VERSION_MAJOR >= 52) && (LIBAVFORMAT_VERSION_MINOR >= 101))
# define FFMPEG_HAVE_PARSE_UTILS 1
# include <libavutil/parseutils.h>
#endif
#include <libswscale/swscale.h>
#if (LIBAVFORMAT_VERSION_MAJOR > 52) || \
((LIBAVFORMAT_VERSION_MAJOR >= 52) && (LIBAVFORMAT_VERSION_MINOR >= 105))
# define FFMPEG_HAVE_AVIO 1
#endif
#if (LIBAVCODEC_VERSION_MAJOR > 53) || \
((LIBAVCODEC_VERSION_MAJOR == 53) && (LIBAVCODEC_VERSION_MINOR > 1)) || \
((LIBAVCODEC_VERSION_MAJOR == 53) && (LIBAVCODEC_VERSION_MINOR == 1) && \
(LIBAVCODEC_VERSION_MICRO >= 1)) || \
((LIBAVCODEC_VERSION_MAJOR == 52) && (LIBAVCODEC_VERSION_MINOR >= 121))
# define FFMPEG_HAVE_DEFAULT_VAL_UNION 1
#endif
#if (LIBAVFORMAT_VERSION_MAJOR > 52) || \
((LIBAVFORMAT_VERSION_MAJOR >= 52) && (LIBAVFORMAT_VERSION_MINOR >= 101))
# define FFMPEG_HAVE_AV_DUMP_FORMAT 1
#endif
#if (LIBAVFORMAT_VERSION_MAJOR > 52) || \
((LIBAVFORMAT_VERSION_MAJOR >= 52) && (LIBAVFORMAT_VERSION_MINOR >= 45))
# define FFMPEG_HAVE_AV_GUESS_FORMAT 1
#endif
#if (LIBAVCODEC_VERSION_MAJOR > 52) || \
((LIBAVCODEC_VERSION_MAJOR >= 52) && (LIBAVCODEC_VERSION_MINOR >= 23))
# define FFMPEG_HAVE_DECODE_AUDIO3 1
# define FFMPEG_HAVE_DECODE_VIDEO2 1
#endif
#if (LIBAVCODEC_VERSION_MAJOR > 52) || \
((LIBAVCODEC_VERSION_MAJOR >= 52) && (LIBAVCODEC_VERSION_MINOR >= 64))
# define FFMPEG_HAVE_AVMEDIA_TYPES 1
#endif
#if ((LIBAVCODEC_VERSION_MAJOR > 52) || \
(LIBAVCODEC_VERSION_MAJOR >= 52) && (LIBAVCODEC_VERSION_MINOR >= 29)) && \
((LIBSWSCALE_VERSION_MAJOR > 0) || \
(LIBSWSCALE_VERSION_MAJOR >= 0) && (LIBSWSCALE_VERSION_MINOR >= 10))
# define FFMPEG_SWSCALE_COLOR_SPACE_SUPPORT
#endif
#if ((LIBAVCODEC_VERSION_MAJOR > 54) || \
(LIBAVCODEC_VERSION_MAJOR >= 54) && (LIBAVCODEC_VERSION_MINOR > 14))
# define FFMPEG_HAVE_CANON_H264_RESOLUTION_FIX
#endif
#if ((LIBAVCODEC_VERSION_MAJOR > 53) || \
(LIBAVCODEC_VERSION_MAJOR >= 53) && (LIBAVCODEC_VERSION_MINOR >= 60))
# define FFMPEG_HAVE_ENCODE_AUDIO2
#endif
#if ((LIBAVCODEC_VERSION_MAJOR > 53) || \
(LIBAVCODEC_VERSION_MAJOR >= 53) && (LIBAVCODEC_VERSION_MINOR >= 42))
# define FFMPEG_HAVE_DECODE_AUDIO4
#endif
#if ((LIBAVCODEC_VERSION_MAJOR > 54) || \
(LIBAVCODEC_VERSION_MAJOR >= 54) && (LIBAVCODEC_VERSION_MINOR >= 13))
# define FFMPEG_HAVE_AVFRAME_SAMPLE_RATE
#endif
#if ((LIBAVUTIL_VERSION_MAJOR > 51) || \
(LIBAVUTIL_VERSION_MAJOR == 51) && (LIBAVUTIL_VERSION_MINOR >= 21))
# define FFMPEG_FFV1_ALPHA_SUPPORTED
# define FFMPEG_SAMPLE_FMT_S16P_SUPPORTED
#else
FFMPEG_INLINE
int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt)
{
/* no planar formats in FFmpeg < 0.9 */
(void)sample_fmt;
return 0;
}
#endif
/* XXX TODO Probably fix to correct modern flags in code? Not sure how old FFMPEG we want to
* support though, so for now this will do. */
#ifndef FF_MIN_BUFFER_SIZE
# ifdef AV_INPUT_BUFFER_MIN_SIZE
# define FF_MIN_BUFFER_SIZE AV_INPUT_BUFFER_MIN_SIZE
# endif
#endif
#ifndef FF_INPUT_BUFFER_PADDING_SIZE
# ifdef AV_INPUT_BUFFER_PADDING_SIZE
# define FF_INPUT_BUFFER_PADDING_SIZE AV_INPUT_BUFFER_PADDING_SIZE
# endif
#endif
#ifndef CODEC_FLAG_GLOBAL_HEADER
# ifdef AV_CODEC_FLAG_GLOBAL_HEADER
# define CODEC_FLAG_GLOBAL_HEADER AV_CODEC_FLAG_GLOBAL_HEADER
# endif
#endif
#ifndef CODEC_FLAG_GLOBAL_HEADER
# ifdef AV_CODEC_FLAG_GLOBAL_HEADER
# define CODEC_FLAG_GLOBAL_HEADER AV_CODEC_FLAG_GLOBAL_HEADER
# endif
#endif
#ifndef CODEC_FLAG_INTERLACED_DCT
# ifdef AV_CODEC_FLAG_INTERLACED_DCT
# define CODEC_FLAG_INTERLACED_DCT AV_CODEC_FLAG_INTERLACED_DCT
# endif
#endif
#ifndef CODEC_FLAG_INTERLACED_ME
# ifdef AV_CODEC_FLAG_INTERLACED_ME
# define CODEC_FLAG_INTERLACED_ME AV_CODEC_FLAG_INTERLACED_ME
# endif
#endif
/* FFmpeg upstream 1.0 is the first who added AV_ prefix. */
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 59, 100)
# define AV_CODEC_ID_NONE CODEC_ID_NONE
# define AV_CODEC_ID_MPEG4 CODEC_ID_MPEG4
# define AV_CODEC_ID_MJPEG CODEC_ID_MJPEG
# define AV_CODEC_ID_DNXHD CODEC_ID_DNXHD
# define AV_CODEC_ID_MPEG2VIDEO CODEC_ID_MPEG2VIDEO
# define AV_CODEC_ID_MPEG1VIDEO CODEC_ID_MPEG1VIDEO
# define AV_CODEC_ID_DVVIDEO CODEC_ID_DVVIDEO
# define AV_CODEC_ID_THEORA CODEC_ID_THEORA
# define AV_CODEC_ID_PNG CODEC_ID_PNG
# define AV_CODEC_ID_QTRLE CODEC_ID_QTRLE
# define AV_CODEC_ID_FFV1 CODEC_ID_FFV1
# define AV_CODEC_ID_HUFFYUV CODEC_ID_HUFFYUV
# define AV_CODEC_ID_H264 CODEC_ID_H264
# define AV_CODEC_ID_FLV1 CODEC_ID_FLV1
# define AV_CODEC_ID_AAC CODEC_ID_AAC
# define AV_CODEC_ID_AC3 CODEC_ID_AC3
# define AV_CODEC_ID_MP3 CODEC_ID_MP3
# define AV_CODEC_ID_MP2 CODEC_ID_MP2
# define AV_CODEC_ID_FLAC CODEC_ID_FLAC
# define AV_CODEC_ID_PCM_U8 CODEC_ID_PCM_U8
# define AV_CODEC_ID_PCM_S16LE CODEC_ID_PCM_S16LE
# define AV_CODEC_ID_PCM_S24LE CODEC_ID_PCM_S24LE
# define AV_CODEC_ID_PCM_S32LE CODEC_ID_PCM_S32LE
# define AV_CODEC_ID_PCM_F32LE CODEC_ID_PCM_F32LE
# define AV_CODEC_ID_PCM_F64LE CODEC_ID_PCM_F64LE
# define AV_CODEC_ID_VORBIS CODEC_ID_VORBIS
#endif
FFMPEG_INLINE
int av_get_cropped_height_from_codec(AVCodecContext *pCodecCtx)
{
int y = pCodecCtx->height;
#ifndef FFMPEG_HAVE_CANON_H264_RESOLUTION_FIX
/* really bad hack to remove this dreadfull black bar at the bottom
with Canon footage and old ffmpeg versions.
(to fix this properly in older ffmpeg versions one has to write a new
demuxer...)
see the actual fix here for reference:
http://git.libav.org/?p=libav.git;a=commit;h=30f515091c323da59c0f1b533703dedca2f4b95d
We do our best to apply this only to matching footage.
*/
if (pCodecCtx->width == 1920 && pCodecCtx->height == 1088 &&
pCodecCtx->pix_fmt == PIX_FMT_YUVJ420P && pCodecCtx->codec_id == AV_CODEC_ID_H264) {
y = 1080;
}
#endif
return y;
}
#if ((LIBAVUTIL_VERSION_MAJOR < 51) || \
(LIBAVUTIL_VERSION_MAJOR == 51) && (LIBAVUTIL_VERSION_MINOR < 22))
FFMPEG_INLINE
int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
{
const AVOption *rv = NULL;
(void)search_flags;
av_set_string3(obj, name, val, 1, &rv);
return rv != NULL;
}
FFMPEG_INLINE
int av_opt_set_int(void *obj, const char *name, int64_t val, int search_flags)
{
const AVOption *rv = NULL;
(void)search_flags;
rv = av_set_int(obj, name, val);
return rv != NULL;
}
FFMPEG_INLINE
int av_opt_set_double(void *obj, const char *name, double val, int search_flags)
{
const AVOption *rv = NULL;
(void)search_flags;
rv = av_set_double(obj, name, val);
return rv != NULL;
}
# define AV_OPT_TYPE_INT FF_OPT_TYPE_INT
# define AV_OPT_TYPE_INT64 FF_OPT_TYPE_INT64
# define AV_OPT_TYPE_STRING FF_OPT_TYPE_STRING
# define AV_OPT_TYPE_CONST FF_OPT_TYPE_CONST
# define AV_OPT_TYPE_DOUBLE FF_OPT_TYPE_DOUBLE
# define AV_OPT_TYPE_FLOAT FF_OPT_TYPE_FLOAT
#endif
#if ((LIBAVUTIL_VERSION_MAJOR < 51) || \
(LIBAVUTIL_VERSION_MAJOR == 51) && (LIBAVUTIL_VERSION_MINOR < 54))
FFMPEG_INLINE
enum AVSampleFormat av_get_packed_sample_fmt(enum AVSampleFormat sample_fmt)
{
if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB)
return AV_SAMPLE_FMT_NONE;
return sample_fmt;
}
#endif
#if ((LIBAVCODEC_VERSION_MAJOR < 53) || \
(LIBAVCODEC_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR < 35))
FFMPEG_INLINE
int avcodec_open2(AVCodecContext *avctx, AVCodec *codec, AVDictionary **options)
{
/* TODO: no options are taking into account */
(void)options;
return avcodec_open(avctx, codec);
}
#endif
#if ((LIBAVFORMAT_VERSION_MAJOR < 53) || \
(LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR < 21))
FFMPEG_INLINE
AVStream *avformat_new_stream(AVFormatContext *s, AVCodec *c)
{
/* TODO: no codec is taking into account */
(void)c;
return av_new_stream(s, 0);
}
FFMPEG_INLINE
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
{
/* TODO: no options are taking into account */
(void)options;
return av_find_stream_info(ic);
}
#endif
#if ((LIBAVFORMAT_VERSION_MAJOR > 53) || \
((LIBAVFORMAT_VERSION_MAJOR == 53) && (LIBAVFORMAT_VERSION_MINOR > 32)) || \
((LIBAVFORMAT_VERSION_MAJOR == 53) && (LIBAVFORMAT_VERSION_MINOR == 24) && \
(LIBAVFORMAT_VERSION_MICRO >= 100)))
FFMPEG_INLINE
void my_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp)
{
@ -323,103 +62,12 @@ void av_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp)
{
my_update_cur_dts(s, ref_st, timestamp);
}
#endif
#if ((LIBAVCODEC_VERSION_MAJOR < 54) || \
(LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR < 28))
FFMPEG_INLINE
void avcodec_free_frame(AVFrame **frame)
{
/* don't need to do anything with old AVFrame
* since it does not have malloced members */
(void)frame;
}
#endif
#if ((LIBAVCODEC_VERSION_MAJOR > 54) || \
(LIBAVCODEC_VERSION_MAJOR >= 54) && (LIBAVCODEC_VERSION_MINOR >= 13))
# define FFMPEG_HAVE_AVFRAME_SAMPLE_RATE
#endif
#if ((LIBAVCODEC_VERSION_MAJOR > 54) || \
(LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 13))
# define FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT
#endif
#ifndef FFMPEG_HAVE_AVIO
# define AVIO_FLAG_WRITE URL_WRONLY
# define avio_open url_fopen
# define avio_tell url_ftell
# define avio_close url_fclose
# define avio_size url_fsize
#endif
/* There are some version in between, which have avio_... functions but no
* AVIO_FLAG_... */
#ifndef AVIO_FLAG_WRITE
# define AVIO_FLAG_WRITE URL_WRONLY
#endif
#ifndef AV_PKT_FLAG_KEY
# define AV_PKT_FLAG_KEY PKT_FLAG_KEY
#endif
#ifndef FFMPEG_HAVE_AV_DUMP_FORMAT
# define av_dump_format dump_format
#endif
#ifndef FFMPEG_HAVE_AV_GUESS_FORMAT
# define av_guess_format guess_format
#endif
#ifndef FFMPEG_HAVE_PARSE_UTILS
# define av_parse_video_rate av_parse_video_frame_rate
#endif
#ifdef FFMPEG_HAVE_DEFAULT_VAL_UNION
# define FFMPEG_DEF_OPT_VAL_INT(OPT) OPT->default_val.i64
# define FFMPEG_DEF_OPT_VAL_DOUBLE(OPT) OPT->default_val.dbl
#else
# define FFMPEG_DEF_OPT_VAL_INT(OPT) OPT->default_val
# define FFMPEG_DEF_OPT_VAL_DOUBLE(OPT) OPT->default_val
#endif
#ifndef FFMPEG_HAVE_AVMEDIA_TYPES
# define AVMEDIA_TYPE_VIDEO CODEC_TYPE_VIDEO
# define AVMEDIA_TYPE_AUDIO CODEC_TYPE_AUDIO
#endif
#ifndef FFMPEG_HAVE_DECODE_AUDIO3
FFMPEG_INLINE
int avcodec_decode_audio3(AVCodecContext *avctx,
int16_t *samples,
int *frame_size_ptr,
AVPacket *avpkt)
{
return avcodec_decode_audio2(avctx, samples, frame_size_ptr, avpkt->data, avpkt->size);
}
#endif
#ifndef FFMPEG_HAVE_DECODE_VIDEO2
FFMPEG_INLINE
int avcodec_decode_video2(AVCodecContext *avctx,
AVFrame *picture,
int *got_picture_ptr,
AVPacket *avpkt)
{
return avcodec_decode_video(avctx, picture, got_picture_ptr, avpkt->data, avpkt->size);
}
#endif
FFMPEG_INLINE
int64_t av_get_pts_from_frame(AVFormatContext *avctx, AVFrame *picture)
{
int64_t pts;
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 34, 100)
pts = picture->pts;
#else
pts = picture->pkt_pts;
#endif
if (pts == AV_NOPTS_VALUE) {
pts = picture->pkt_dts;
@ -432,124 +80,16 @@ int64_t av_get_pts_from_frame(AVFormatContext *avctx, AVFrame *picture)
return pts;
}
/* obsolete constant formerly defined in FFMpeg libavcodec/avcodec.h */
#ifndef AVCODEC_MAX_AUDIO_FRAME_SIZE
# define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
#endif
/* -------------------------------------------------------------------- */
/** \name Deinterlace code block
*
* NOTE: The code in this block are from FFmpeg 2.6.4, which is licensed by LGPL.
* \{ */
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 1, 0)
FFMPEG_INLINE
int avcodec_encode_video2(AVCodecContext *avctx,
AVPacket *pkt,
const AVFrame *frame,
int *got_output)
{
int outsize, ret;
#define MAX_NEG_CROP 1024
ret = av_new_packet(pkt, avctx->width * avctx->height * 7 + 10000);
if (ret < 0)
return ret;
outsize = avcodec_encode_video(avctx, pkt->data, pkt->size, frame);
if (outsize <= 0) {
*got_output = 0;
av_free_packet(pkt);
}
else {
*got_output = 1;
av_shrink_packet(pkt, outsize);
if (avctx->coded_frame) {
pkt->pts = avctx->coded_frame->pts;
if (avctx->coded_frame->key_frame)
pkt->flags |= AV_PKT_FLAG_KEY;
}
}
return outsize >= 0 ? 0 : outsize;
}
#endif
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 17, 0)
FFMPEG_INLINE
void avformat_close_input(AVFormatContext **ctx)
{
av_close_input_file(*ctx);
*ctx = NULL;
}
#endif
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 8, 0)
FFMPEG_INLINE
AVFrame *av_frame_alloc(void)
{
return avcodec_alloc_frame();
}
FFMPEG_INLINE
void av_frame_free(AVFrame **frame)
{
av_freep(frame);
}
#endif
FFMPEG_INLINE
const char *av_get_metadata_key_value(AVDictionary *metadata, const char *key)
{
if (metadata == NULL) {
return NULL;
}
AVDictionaryEntry *tag = NULL;
while ((tag = av_dict_get(metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
if (!strcmp(tag->key, key)) {
return tag->value;
}
}
return NULL;
}
FFMPEG_INLINE
bool av_check_encoded_with_ffmpeg(AVFormatContext *ctx)
{
const char *encoder = av_get_metadata_key_value(ctx->metadata, "ENCODER");
if (encoder != NULL && !strncmp(encoder, "Lavf", 4)) {
return true;
}
return false;
}
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51, 32, 0)
# define AV_OPT_SEARCH_FAKE_OBJ 0
#endif
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 59, 100)
# define FFMPEG_HAVE_DEPRECATED_FLAGS2
#endif
/* Since FFmpeg-1.1 this constant have AV_ prefix. */
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 3, 100)
# define AV_PIX_FMT_BGR32 PIX_FMT_BGR32
# define AV_PIX_FMT_YUV422P PIX_FMT_YUV422P
# define AV_PIX_FMT_BGRA PIX_FMT_BGRA
# define AV_PIX_FMT_ARGB PIX_FMT_ARGB
# define AV_PIX_FMT_RGBA PIX_FMT_RGBA
#endif
/* New API from FFmpeg-2.0 which soon became recommended one. */
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 38, 100)
# define av_frame_alloc avcodec_alloc_frame
# define av_frame_free avcodec_free_frame
# define av_frame_unref avcodec_get_frame_defaults
#endif
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 24, 102)
/* NOTE: The code in this block are from FFmpeg 2.6.4, which is licensed by LGPL. */
# define MAX_NEG_CROP 1024
# define times4(x) x, x, x, x
# define times256(x) times4(times4(times4(times4(times4(x)))))
#define times4(x) x, x, x, x
#define times256(x) times4(times4(times4(times4(times4(x)))))
static const uint8_t ff_compat_crop_tab[256 + 2 * MAX_NEG_CROP] = {
times256(0x00), 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
@ -575,8 +115,8 @@ static const uint8_t ff_compat_crop_tab[256 + 2 * MAX_NEG_CROP] = {
0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA,
0xFB, 0xFC, 0xFD, 0xFE, 0xFF, times256(0xFF)};
# undef times4
# undef times256
#undef times4
#undef times256
/* filter parameters: [-1 4 2 4 -1] // 8 */
FFMPEG_INLINE
@ -668,8 +208,9 @@ int deinterlace_bottom_field_inplace(uint8_t *src1, int src_wrap, int width, int
uint8_t *src_m1, *src_0, *src_p1, *src_p2;
int y;
uint8_t *buf = (uint8_t *)av_malloc(width);
if (!buf)
if (!buf) {
return AVERROR(ENOMEM);
}
src_m1 = src1;
memcpy(buf, src_m1, width);
@ -689,24 +230,21 @@ int deinterlace_bottom_field_inplace(uint8_t *src1, int src_wrap, int width, int
return 0;
}
# ifdef __GNUC__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
# endif
FFMPEG_INLINE
int avpicture_deinterlace(
AVPicture *dst, const AVPicture *src, enum AVPixelFormat pix_fmt, int width, int height)
int av_image_deinterlace(
AVFrame *dst, const AVFrame *src, enum AVPixelFormat pix_fmt, int width, int height)
{
int i, ret;
if (pix_fmt != AV_PIX_FMT_YUV420P && pix_fmt != AV_PIX_FMT_YUVJ420P &&
pix_fmt != AV_PIX_FMT_YUV422P && pix_fmt != AV_PIX_FMT_YUVJ422P &&
pix_fmt != AV_PIX_FMT_YUV444P && pix_fmt != AV_PIX_FMT_YUV411P &&
pix_fmt != AV_PIX_FMT_GRAY8)
pix_fmt != AV_PIX_FMT_GRAY8) {
return -1;
if ((width & 3) != 0 || (height & 3) != 0)
}
if ((width & 3) != 0 || (height & 3) != 0) {
return -1;
}
for (i = 0; i < 3; i++) {
if (i == 1) {
@ -732,8 +270,9 @@ int avpicture_deinterlace(
}
if (src == dst) {
ret = deinterlace_bottom_field_inplace(dst->data[i], dst->linesize[i], width, height);
if (ret < 0)
if (ret < 0) {
return ret;
}
}
else {
deinterlace_bottom_field(
@ -743,10 +282,6 @@ int avpicture_deinterlace(
return 0;
}
# ifdef __GNUC__
# pragma GCC diagnostic pop
# endif
#endif
/** \} Deinterlace code block */
#endif

View File

@ -276,7 +276,7 @@ extern int GHOST_GetFullScreen(GHOST_SystemHandle systemhandle);
* wait (block) until the next event before returning.
* \return Indication of the presence of events.
*/
extern int GHOST_ProcessEvents(GHOST_SystemHandle systemhandle, int waitForEvent);
extern bool GHOST_ProcessEvents(GHOST_SystemHandle systemhandle, bool waitForEvent);
/**
* Retrieves events from the queue and send them to the event consumers.

View File

@ -416,7 +416,10 @@ typedef enum {
GHOST_kGrabNormal,
/** Wrap the mouse location to prevent limiting screen bounds. */
GHOST_kGrabWrap,
/** Hide the mouse while grabbing and restore the original location on release (numbuts). */
/**
* Hide the mouse while grabbing and restore the original location on release
* (used for number buttons and some other draggable UI elements).
*/
GHOST_kGrabHide,
} GHOST_TGrabCursorMode;

View File

@ -248,11 +248,11 @@ int GHOST_GetFullScreen(GHOST_SystemHandle systemhandle)
return (int)system->getFullScreen();
}
int GHOST_ProcessEvents(GHOST_SystemHandle systemhandle, int waitForEvent)
bool GHOST_ProcessEvents(GHOST_SystemHandle systemhandle, bool waitForEvent)
{
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
return (int)system->processEvents(waitForEvent ? true : false);
return system->processEvents(waitForEvent);
}
void GHOST_DispatchEvents(GHOST_SystemHandle systemhandle)

View File

@ -112,8 +112,7 @@ GHOST_DropTargetX11::~GHOST_DropTargetX11()
}
}
/* based on a code from Saul Rennison
* http://stackoverflow.com/questions/2673207/c-c-url-decode-library */
/* Based on: https://stackoverflow.com/a/2766963/432509 */
typedef enum DecodeState_e {
STATE_SEARCH = 0, ///< searching for an ampersand to convert

View File

@ -1711,7 +1711,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
dx = [event scrollingDeltaX];
dy = [event scrollingDeltaY];
/* However, wacom tablet (intuos5) needs old deltas,
/* However, Wacom tablet (intuos5) needs old deltas,
* it then has momentum and phase at zero. */
if (phase == NSEventPhaseNone && momentumPhase == NSEventPhaseNone) {
dx = [event deltaX];

View File

@ -477,7 +477,7 @@ int main(int argc, char **argv)
/* Enter main loop */
while (!sExitRequested) {
if (!GHOST_ProcessEvents(shSystem, 0)) {
if (!GHOST_ProcessEvents(shSystem, false)) {
#ifdef WIN32
/* If there were no events, be nice to other applications */
Sleep(10);

View File

@ -926,7 +926,7 @@ void multitestapp_exit(MultiTestApp *app)
void multitestapp_run(MultiTestApp *app)
{
while (!app->exit) {
GHOST_ProcessEvents(app->sys, 1);
GHOST_ProcessEvents(app->sys, true);
GHOST_DispatchEvents(app->sys);
}
}

@ -1 +1 @@
Subproject commit f7b706dd6434db2d752f47c4b8c3148b2990fd73
Subproject commit 2cef4877edc40875978c4e95322bb5193f5815bf

@ -1 +1 @@
Subproject commit 4cb833e84acfd2be5fa08ce75118ce9cb60643b8
Subproject commit bcd08a9506d33bdd7358201031b04d041ef22d94

@ -1 +1 @@
Subproject commit 8970953d4a8a4ea3bf77c66370c817ed0cf1308a
Subproject commit f948f658ba33eb670a65e0bba058d43138abea7e

View File

@ -119,6 +119,7 @@ class SpellChecker:
"dirtree",
"editcurve",
"editmesh",
"faceforward",
"filebrowser",
"filelist",
"filename", "filenames",
@ -200,6 +201,7 @@ class SpellChecker:
"selfcollision",
"shadowbuffer", "shadowbuffers",
"singletexture",
"softbox",
"spellcheck", "spellchecking",
"startup",
"stateful",

View File

@ -657,16 +657,14 @@ class Gizmo(StructRNA):
use_blend = color[3] < 1.0
if use_blend:
# TODO: wrap GPU_blend from GPU state.
from bgl import glEnable, glDisable, GL_BLEND
glEnable(GL_BLEND)
gpu.state.blend_set('ALPHA')
with gpu.matrix.push_pop():
gpu.matrix.multiply_matrix(matrix)
batch.draw()
if use_blend:
glDisable(GL_BLEND)
gpu.state.blend_set('NONE')
@staticmethod
def new_custom_shape(type, verts):

View File

@ -57,12 +57,12 @@ def draw_circle_2d(position, color, radius, segments=32):
batch.draw()
def draw_texture_2d(texture_id, position, width, height):
def draw_texture_2d(texture, position, width, height):
"""
Draw a 2d texture.
:arg texture_id: OpenGL id of the texture (e.g. :class:`bpy.types.Image.bindcode`).
:type texture_id: int
:arg texture: GPUTexture to draw (e.g. gpu.texture.from_image(image) for :class:`bpy.types.Image`).
:type texture: :class:`gpu.types.GPUTexture`
:arg position: Position of the lower left corner.
:type position: 2D Vector
:arg width: Width of the image when drawn (not necessarily
@ -72,7 +72,6 @@ def draw_texture_2d(texture_id, position, width, height):
:type height: float
"""
import gpu
import bgl
from . batch import batch_for_shader
coords = ((0, 0), (1, 0), (1, 1), (0, 1))
@ -83,14 +82,20 @@ def draw_texture_2d(texture_id, position, width, height):
{"pos": coords, "texCoord": coords},
)
bgl.glActiveTexture(bgl.GL_TEXTURE0)
bgl.glBindTexture(bgl.GL_TEXTURE_2D, texture_id)
with gpu.matrix.push_pop():
gpu.matrix.translate(position)
gpu.matrix.scale((width, height))
shader = gpu.shader.from_builtin('2D_IMAGE')
shader.bind()
shader.uniform_int("image", 0)
if isinstance(texture, int):
# Call the legacy bgl to not break the existing API
import bgl
bgl.glActiveTexture(bgl.GL_TEXTURE0)
bgl.glBindTexture(bgl.GL_TEXTURE_2D, texture)
shader.uniform_int("image", 0)
else:
shader.uniform_sampler("image", texture)
batch.draw(shader)

View File

@ -305,7 +305,7 @@ url_manual_mapping = (
("bpy.types.geometrynodealignrotationtovector*", "modeling/geometry_nodes/point/align_rotation_to_vector.html#bpy-types-geometrynodealignrotationtovector"),
("bpy.types.greasepencil.curve_edit_threshold*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-curve-edit-threshold"),
("bpy.types.materialgpencilstyle.stroke_style*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-stroke-style"),
("bpy.types.objectlineart.use_crease_override*", "scene_layout/object/properties/lineart.html#bpy-types-objectlineart-use-crease-override"),
("bpy.types.objectlineart.use_crease_override*", "scene_layout/object/properties/line_art.html#bpy-types-objectlineart-use-crease-override"),
("bpy.types.rendersettings.preview_pixel_size*", "render/cycles/render_settings/performance.html#bpy-types-rendersettings-preview-pixel-size"),
("bpy.types.rendersettings.use_crop_to_border*", "render/output/properties/dimensions.html#bpy-types-rendersettings-use-crop-to-border"),
("bpy.types.rendersettings.use_file_extension*", "render/output/properties/output.html#bpy-types-rendersettings-use-file-extension"),
@ -449,7 +449,7 @@ url_manual_mapping = (
("bpy.types.nodesocketinterface*.max_value*", "interface/controls/nodes/groups.html#bpy-types-nodesocketinterface-max-value"),
("bpy.types.nodesocketinterface*.min_value*", "interface/controls/nodes/groups.html#bpy-types-nodesocketinterface-min-value"),
("bpy.types.nodesocketinterface.hide_value*", "interface/controls/nodes/groups.html#bpy-types-nodesocketinterface-hide-value"),
("bpy.types.objectlineart.crease_threshold*", "scene_layout/object/properties/lineart.html#bpy-types-objectlineart-crease-threshold"),
("bpy.types.objectlineart.crease_threshold*", "scene_layout/object/properties/line_art.html#bpy-types-objectlineart-crease-threshold"),
("bpy.types.rendersettings.use_compositing*", "render/output/properties/post_processing.html#bpy-types-rendersettings-use-compositing"),
("bpy.types.rendersettings.use_placeholder*", "render/output/properties/output.html#bpy-types-rendersettings-use-placeholder"),
("bpy.types.shadernodesubsurfacescattering*", "render/shader_nodes/shader/sss.html#bpy-types-shadernodesubsurfacescattering"),
@ -487,6 +487,7 @@ url_manual_mapping = (
("bpy.types.fluidflowsettings.temperature*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-temperature"),
("bpy.types.fluidflowsettings.use_texture*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-use-texture"),
("bpy.types.fmodifierenvelopecontrolpoint*", "editors/graph_editor/fcurves/sidebar/modifiers.html#bpy-types-fmodifierenvelopecontrolpoint"),
("bpy.types.geometrynodeattributemaprange*", "modeling/geometry_nodes/attribute/attribute_map_range.html#bpy-types-geometrynodeattributemaprange"),
("bpy.types.layercollection.hide_viewport*", "editors/outliner/interface.html#bpy-types-layercollection-hide-viewport"),
("bpy.types.layercollection.indirect_only*", "editors/outliner/interface.html#bpy-types-layercollection-indirect-only"),
("bpy.types.material.use_sss_translucency*", "render/eevee/materials/settings.html#bpy-types-material-use-sss-translucency"),
@ -947,7 +948,7 @@ url_manual_mapping = (
("bpy.types.imagepaint.use_occlude*", "sculpt_paint/texture_paint/tool_settings/options.html#bpy-types-imagepaint-use-occlude"),
("bpy.types.imagesequence.use_flip*", "video_editing/sequencer/sidebar/strip.html#bpy-types-imagesequence-use-flip"),
("bpy.types.latticegpencilmodifier*", "grease_pencil/modifiers/deform/lattice.html#bpy-types-latticegpencilmodifier"),
("bpy.types.lineartgpencilmodifier*", "grease_pencil/modifiers/generate/lineart.html#bpy-types-lineartgpencilmodifier"),
("bpy.types.lineartgpencilmodifier*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier"),
("bpy.types.mesh.auto_smooth_angle*", "modeling/meshes/structure.html#bpy-types-mesh-auto-smooth-angle"),
("bpy.types.objectsolverconstraint*", "animation/constraints/motion_tracking/object_solver.html#bpy-types-objectsolverconstraint"),
("bpy.types.opacitygpencilmodifier*", "grease_pencil/modifiers/color/opacity.html#bpy-types-opacitygpencilmodifier"),
@ -1110,6 +1111,7 @@ url_manual_mapping = (
("bpy.types.ffmpegsettings.audio*", "render/output/properties/output.html#bpy-types-ffmpegsettings-audio"),
("bpy.types.followpathconstraint*", "animation/constraints/relationship/follow_path.html#bpy-types-followpathconstraint"),
("bpy.types.gaussianblursequence*", "video_editing/sequencer/strips/effects/blur.html#bpy-types-gaussianblursequence"),
("bpy.types.geometrynodeboundbox*", "modeling/geometry_nodes/geometry/bounding_box.html#bpy-types-geometrynodeboundbox"),
("bpy.types.geometrynodemeshcone*", "modeling/geometry_nodes/mesh_primitives/cone.html#bpy-types-geometrynodemeshcone"),
("bpy.types.geometrynodemeshcube*", "modeling/geometry_nodes/mesh_primitives/cube.html#bpy-types-geometrynodemeshcube"),
("bpy.types.geometrynodemeshgrid*", "modeling/geometry_nodes/mesh_primitives/grid.html#bpy-types-geometrynodemeshgrid"),
@ -1152,6 +1154,7 @@ url_manual_mapping = (
("bpy.ops.clip.set_scene_frames*", "movie_clip/tracking/clip/editing/clip.html#bpy-ops-clip-set-scene-frames"),
("bpy.ops.curve.handle_type_set*", "modeling/curves/editing/control_points.html#bpy-ops-curve-handle-type-set"),
("bpy.ops.curve.spline_type_set*", "modeling/curves/editing/curve.html#bpy-ops-curve-spline-type-set"),
("bpy.ops.file.unpack_libraries*", "files/blend/packed_data.html#bpy-ops-file-unpack-libraries"),
("bpy.ops.gpencil.move_to_layer*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-move-to-layer"),
("bpy.ops.gpencil.stroke_sample*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-sample"),
("bpy.ops.gpencil.stroke_smooth*", "grease_pencil/modes/edit/point_menu.html#bpy-ops-gpencil-stroke-smooth"),
@ -1219,7 +1222,7 @@ url_manual_mapping = (
("bpy.types.mesh.use_paint_mask*", "sculpt_paint/brush/introduction.html#bpy-types-mesh-use-paint-mask"),
("bpy.types.movietrackingcamera*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera"),
("bpy.types.object.display_type*", "scene_layout/object/properties/display.html#bpy-types-object-display-type"),
("bpy.types.objectlineart.usage*", "scene_layout/object/properties/lineart.html#bpy-types-objectlineart-usage"),
("bpy.types.objectlineart.usage*", "scene_layout/object/properties/line_art.html#bpy-types-objectlineart-usage"),
("bpy.types.particledupliweight*", "physics/particles/emitter/vertex_groups.html#bpy-types-particledupliweight"),
("bpy.types.poseboneconstraints*", "animation/armatures/posing/bone_constraints/index.html#bpy-types-poseboneconstraints"),
("bpy.types.rigidbodyconstraint*", "physics/rigid_body/constraints/index.html#bpy-types-rigidbodyconstraint"),
@ -1260,6 +1263,7 @@ url_manual_mapping = (
("bpy.ops.console.autocomplete*", "editors/python_console.html#bpy-ops-console-autocomplete"),
("bpy.ops.curve.dissolve_verts*", "modeling/curves/editing/curve.html#bpy-ops-curve-dissolve-verts"),
("bpy.ops.curve.duplicate_move*", "modeling/curves/editing/curve.html#bpy-ops-curve-duplicate-move"),
("bpy.ops.file.autopack_toggle*", "files/blend/packed_data.html#bpy-ops-file-autopack-toggle"),
("bpy.ops.fluid.bake_particles*", "physics/fluid/type/domain/liquid/particles.html#bpy-ops-fluid-bake-particles"),
("bpy.ops.fluid.free_particles*", "physics/fluid/type/domain/liquid/particles.html#bpy-ops-fluid-free-particles"),
("bpy.ops.gpencil.extrude_move*", "grease_pencil/modes/edit/point_menu.html#bpy-ops-gpencil-extrude-move"),
@ -1297,6 +1301,7 @@ url_manual_mapping = (
("bpy.types.alphaundersequence*", "video_editing/sequencer/strips/effects/alpha_over_under_overdrop.html#bpy-types-alphaundersequence"),
("bpy.types.armature.show_axes*", "animation/armatures/properties/display.html#bpy-types-armature-show-axes"),
("bpy.types.armatureconstraint*", "animation/constraints/relationship/armature.html#bpy-types-armatureconstraint"),
("bpy.types.compositornodeblur*", "compositing/types/filter/blur_node.html#bpy-types-compositornodeblur"),
("bpy.types.compositornodecomb*", "editors/texture_node/types/color/combine_separate.html#bpy-types-compositornodecomb"),
("bpy.types.compositornodecrop*", "compositing/types/distort/crop.html#bpy-types-compositornodecrop"),
("bpy.types.compositornodeflip*", "compositing/types/distort/flip.html#bpy-types-compositornodeflip"),
@ -1358,6 +1363,7 @@ url_manual_mapping = (
("bpy.ops.curve.primitive*add*", "modeling/curves/primitives.html#bpy-ops-curve-primitive-add"),
("bpy.ops.curve.smooth_radius*", "modeling/curves/editing/control_points.html#bpy-ops-curve-smooth-radius"),
("bpy.ops.curve.smooth_weight*", "modeling/curves/editing/control_points.html#bpy-ops-curve-smooth-weight"),
("bpy.ops.file.pack_libraries*", "files/blend/packed_data.html#bpy-ops-file-pack-libraries"),
("bpy.ops.font.change_spacing*", "modeling/texts/editing.html#bpy-ops-font-change-spacing"),
("bpy.ops.gpencil.stroke_flip*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-flip"),
("bpy.ops.gpencil.stroke_join*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-join"),
@ -1453,7 +1459,7 @@ url_manual_mapping = (
("bpy.types.viewlayer.use_sky*", "render/layers/introduction.html#bpy-types-viewlayer-use-sky"),
("bpy.types.wireframemodifier*", "modeling/modifiers/generate/wireframe.html#bpy-types-wireframemodifier"),
("bpy.types.worldmistsettings*", "render/cycles/world_settings.html#bpy-types-worldmistsettings"),
("bpy.ops.anim.channels_move*", "editors/nla/editing.html#bpy-ops-anim-channels-move"),
("bpy.ops.anim.channels_move*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-move"),
("bpy.ops.buttons.toggle_pin*", "editors/properties_editor.html#bpy-ops-buttons-toggle-pin"),
("bpy.ops.clip.filter_tracks*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-filter-tracks"),
("bpy.ops.clip.select_circle*", "movie_clip/tracking/clip/selecting.html#bpy-ops-clip-select-circle"),
@ -1691,6 +1697,7 @@ url_manual_mapping = (
("bpy.ops.clip.set_origin*", "movie_clip/tracking/clip/editing/reconstruction.html#bpy-ops-clip-set-origin"),
("bpy.ops.curve.subdivide*", "modeling/curves/editing/segments.html#bpy-ops-curve-subdivide"),
("bpy.ops.ed.undo_history*", "interface/undo_redo.html#bpy-ops-ed-undo-history"),
("bpy.ops.file.unpack_all*", "files/blend/packed_data.html#bpy-ops-file-unpack-all"),
("bpy.ops.fluid.bake_data*", "physics/fluid/type/domain/settings.html#bpy-ops-fluid-bake-data"),
("bpy.ops.fluid.bake_mesh*", "physics/fluid/type/domain/liquid/mesh.html#bpy-ops-fluid-bake-mesh"),
("bpy.ops.fluid.free_data*", "physics/fluid/type/domain/settings.html#bpy-ops-fluid-free-data"),
@ -1749,7 +1756,7 @@ url_manual_mapping = (
("bpy.types.nlastrip.name*", "editors/nla/sidebar.html#bpy-types-nlastrip-name"),
("bpy.types.nodesmodifier*", "modeling/modifiers/generate/geometry_nodes.html#bpy-types-nodesmodifier"),
("bpy.types.object.parent*", "scene_layout/object/editing/parent.html#bpy-types-object-parent"),
("bpy.types.objectlineart*", "scene_layout/object/properties/lineart.html#bpy-types-objectlineart"),
("bpy.types.objectlineart*", "scene_layout/object/properties/line_art.html#bpy-types-objectlineart"),
("bpy.types.oceanmodifier*", "modeling/modifiers/physics/ocean.html#bpy-types-oceanmodifier"),
("bpy.types.particlebrush*", "physics/particles/mode.html#bpy-types-particlebrush"),
("bpy.types.scene.gravity*", "physics/forces/gravity.html#bpy-types-scene-gravity"),
@ -1845,6 +1852,7 @@ url_manual_mapping = (
("bpy.types.wipesequence*", "video_editing/sequencer/strips/transitions/wipe.html#bpy-types-wipesequence"),
("bpy.ops.clip.prefetch*", "movie_clip/tracking/clip/editing/clip.html#bpy-ops-clip-prefetch"),
("bpy.ops.clip.set_axis*", "movie_clip/tracking/clip/editing/reconstruction.html#bpy-ops-clip-set-axis"),
("bpy.ops.file.pack_all*", "files/blend/packed_data.html#bpy-ops-file-pack-all"),
("bpy.ops.gpencil.paste*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-paste"),
("bpy.ops.image.project*", "sculpt_paint/texture_paint/tool_settings/options.html#bpy-ops-image-project"),
("bpy.ops.material.copy*", "render/materials/assignment.html#bpy-ops-material-copy"),

View File

@ -23,6 +23,7 @@
def write_sysinfo(filepath):
import sys
import platform
import subprocess
@ -63,7 +64,7 @@ def write_sysinfo(filepath):
))
output.write("build date: %s, %s\n" % (prepr(bpy.app.build_date), prepr(bpy.app.build_time)))
output.write("platform: %s\n" % prepr(bpy.app.build_platform))
output.write("platform: %s\n" % prepr(platform.platform()))
output.write("binary path: %s\n" % prepr(bpy.app.binary_path))
output.write("build cflags: %s\n" % prepr(bpy.app.build_cflags))
output.write("build cxxflags: %s\n" % prepr(bpy.app.build_cxxflags))

View File

@ -278,15 +278,11 @@ def _template_items_uv_select_mode(params):
else:
return [
*_template_items_editmode_mesh_select_mode(params),
# Hack to prevent fall-through, when sync select isn't enabled (and the island button isn't visible).
("mesh.select_mode", {"type": 'FOUR', "value": 'PRESS'}, None),
("wm.context_set_enum", {"type": 'ONE', "value": 'PRESS'},
{"properties": [("data_path", 'tool_settings.uv_select_mode'), ("value", 'VERTEX')]}),
("wm.context_set_enum", {"type": 'TWO', "value": 'PRESS'},
{"properties": [("data_path", 'tool_settings.uv_select_mode'), ("value", 'EDGE')]}),
("wm.context_set_enum", {"type": 'THREE', "value": 'PRESS'},
{"properties": [("data_path", 'tool_settings.uv_select_mode'), ("value", 'FACE')]}),
("wm.context_set_enum", {"type": 'FOUR', "value": 'PRESS'},
{"properties": [("data_path", 'tool_settings.uv_select_mode'), ("value", 'ISLAND')]}),
*(("wm.context_set_enum", {"type": NUMBERS_1[i], "value": 'PRESS'},
{"properties": [("data_path", 'tool_settings.uv_select_mode'), ("value", ty)]})
for i, ty in enumerate(('VERTEX', 'EDGE', 'FACE', 'ISLAND')))
]
@ -2009,8 +2005,7 @@ def km_file_browser_main(params):
)
items.extend([
("file.execute", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'},
{"properties": [("need_active", True)]}),
("file.mouse_execute", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
# Both .execute and .select are needed here. The former only works if
# there's a file operator (i.e. not in regular editor mode) but is
# needed to load files. The latter makes selection work if there's no
@ -3382,6 +3377,11 @@ def km_grease_pencil_stroke_paint_mode(params):
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_paint.brush.size')]}),
# Increase/Decrease brush size
("brush.scale_size", {"type": 'LEFT_BRACKET', "value": 'PRESS', "repeat": True},
{"properties": [("scalar", 0.9)]}),
("brush.scale_size", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "repeat": True},
{"properties": [("scalar", 1.0 / 0.9)]}),
# Draw delete menu
op_menu("GPENCIL_MT_gpencil_draw_delete", {"type": 'X', "value": 'PRESS'}),
# Animation menu
@ -3549,6 +3549,11 @@ def km_grease_pencil_stroke_sculpt_mode(params):
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_sculpt_paint.brush.size')]}),
# Increase/Decrease brush size
("brush.scale_size", {"type": 'LEFT_BRACKET', "value": 'PRESS', "repeat": True},
{"properties": [("scalar", 0.9)]}),
("brush.scale_size", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "repeat": True},
{"properties": [("scalar", 1.0 / 0.9)]}),
# Copy
("gpencil.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None),
# Display
@ -3763,6 +3768,11 @@ def km_grease_pencil_stroke_weight_mode(params):
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_weight_paint.brush.size')]}),
# Increase/Decrease brush size
("brush.scale_size", {"type": 'LEFT_BRACKET', "value": 'PRESS', "repeat": True},
{"properties": [("scalar", 0.9)]}),
("brush.scale_size", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "repeat": True},
{"properties": [("scalar", 1.0 / 0.9)]}),
# Display
*_grease_pencil_display(),
# Keyframe menu
@ -3820,6 +3830,11 @@ def km_grease_pencil_stroke_vertex_mode(params):
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.size')]}),
# Increase/Decrease brush size
("brush.scale_size", {"type": 'LEFT_BRACKET', "value": 'PRESS', "repeat": True},
{"properties": [("scalar", 0.9)]}),
("brush.scale_size", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "repeat": True},
{"properties": [("scalar", 1.0 / 0.9)]}),
# Display
*_grease_pencil_display(),
# Tools

View File

@ -1263,8 +1263,7 @@ def km_file_browser_main(params):
)
items.extend([
("file.execute", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'},
{"properties": [("need_active", True)]}),
("file.mouse_execute", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
("file.refresh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
("file.select", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK'},

View File

@ -130,6 +130,7 @@ class PlayRenderedAnim(Operator):
"-s", str(frame_start),
"-e", str(frame_end),
"-j", str(scene.frame_step),
"-c", str(prefs.system.memory_cache_limit),
file,
]
cmd.extend(opts)

View File

@ -113,7 +113,8 @@ class GPENCIL_MT_layer_context_menu(Menu):
layout.operator("gpencil.layer_merge", icon='SORT_ASC', text="Merge Down")
layout.separator()
layout.menu("VIEW3D_MT_gpencil_copy_layer")
layout.menu("VIEW3D_MT_gpencil_append_active_layer")
layout.menu("VIEW3D_MT_gpencil_append_all_layers")
class DATA_PT_gpencil_layers(DataButtonsPanel, Panel):

View File

@ -53,6 +53,10 @@ class GPENCIL_MT_material_context_menu(Menu):
layout.operator("gpencil.material_to_vertex_color", text="Convert Materials to Vertex Color")
layout.operator("gpencil.extract_palette_vertex", text="Extract Palette from Vertex Color")
layout.separator()
layout.menu("VIEW3D_MT_gpencil_append_active_material")
layout.menu("VIEW3D_MT_gpencil_append_all_materials")
class GPENCIL_UL_matslots(UIList):
def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):

View File

@ -1235,7 +1235,7 @@ def brush_basic_gpencil_paint_settings(layout, context, brush, *, compact=False)
row = layout.row(align=True)
row.prop(gp_settings, "fill_factor")
row = layout.row(align=True)
row.prop(gp_settings, "fill_leak", text="Leak Size")
row.prop(gp_settings, "dilate")
row = layout.row(align=True)
row.prop(brush, "size", text="Thickness")
layout.use_property_split = use_property_split_prev

View File

@ -300,6 +300,8 @@ class TIME_PT_keyframing_settings(TimelinePanelButtons, Panel):
col.label(text="New Keyframe Type")
col.prop(tool_settings, "keyframe_type", text="")
layout.prop(tool_settings, "use_keyframe_cycle_aware")
class TIME_PT_auto_keyframing(TimelinePanelButtons, Panel):
bl_label = "Auto Keyframing"
@ -327,8 +329,6 @@ class TIME_PT_auto_keyframing(TimelinePanelButtons, Panel):
if not prefs.edit.use_keyframe_insert_available:
col.prop(tool_settings, "use_record_with_nla", text="Layered Recording")
col.prop(tool_settings, "use_keyframe_cycle_aware")
###################################

View File

@ -504,8 +504,6 @@ class TOPBAR_MT_file_external_data(Menu):
icon = 'CHECKBOX_HLT' if bpy.data.use_autopack else 'CHECKBOX_DEHLT'
layout.operator("file.autopack_toggle", icon=icon)
layout.separator()
pack_all = layout.row()
pack_all.operator("file.pack_all")
pack_all.active = not bpy.data.use_autopack
@ -516,8 +514,16 @@ class TOPBAR_MT_file_external_data(Menu):
layout.separator()
layout.operator("file.pack_libraries")
layout.operator("file.unpack_libraries")
layout.separator()
layout.operator("file.make_paths_relative")
layout.operator("file.make_paths_absolute")
layout.separator()
layout.operator("file.report_missing_files")
layout.operator("file.find_missing_files")

View File

@ -938,7 +938,8 @@ class VIEW3D_MT_transform_base:
layout.operator("transform.bend", text="Bend")
layout.operator("transform.push_pull", text="Push/Pull")
if context.mode != 'OBJECT':
if context.mode in {'EDIT_MESH', 'EDIT_ARMATURE', 'EDIT_SURFACE', 'EDIT_CURVE',
'EDIT_LATTICE', 'EDIT_METABALL'}:
layout.operator("transform.vertex_warp", text="Warp")
layout.operator_context = 'EXEC_REGION_WIN'
layout.operator("transform.vertex_random", text="Randomize").offset = 0.1
@ -4963,26 +4964,73 @@ class VIEW3D_MT_assign_material(Menu):
icon='LAYER_ACTIVE' if mat == mat_active else 'BLANK1').material = mat.name
class VIEW3D_MT_gpencil_copy_layer(Menu):
bl_label = "Copy Layer to Object"
def gpencil_layer_append_menu_items(context, layout, only_active):
done = False
view_layer = context.view_layer
obact = context.active_object
gpl = context.active_gpencil_layer
done = False
if gpl is not None:
for ob in view_layer.objects:
if ob.type == 'GPENCIL' and ob != obact:
op = layout.operator("gpencil.layer_duplicate_object", text=ob.name)
op.object = ob.name
op.only_active = only_active
done = True
if done is False:
layout.label(text="No destination object", icon='ERROR')
else:
layout.label(text="No layer to copy", icon='ERROR')
class VIEW3D_MT_gpencil_append_active_layer(Menu):
bl_label = "Append Active Layer to Object"
def draw(self, context):
layout = self.layout
view_layer = context.view_layer
obact = context.active_object
gpl = context.active_gpencil_layer
gpencil_layer_append_menu_items(context, layout, True)
done = False
if gpl is not None:
for ob in view_layer.objects:
if ob.type == 'GPENCIL' and ob != obact:
layout.operator("gpencil.layer_duplicate_object", text=ob.name).object = ob.name
done = True
if done is False:
layout.label(text="No destination object", icon='ERROR')
else:
layout.label(text="No layer to copy", icon='ERROR')
class VIEW3D_MT_gpencil_append_all_layers(Menu):
bl_label = "Append All Layers to Object"
def draw(self, context):
layout = self.layout
gpencil_layer_append_menu_items(context, layout, False)
def gpencil_material_menu_items(context, layout, only_selected):
done = False
view_layer = context.view_layer
obact = context.active_object
for ob in view_layer.objects:
if ob.type == 'GPENCIL' and ob != obact:
op = layout.operator("gpencil.materials_append_to_object", text=ob.name)
op.object = ob.name
op.only_selected = only_selected
done = True
if done is False:
layout.label(text="No destination object", icon='ERROR')
class VIEW3D_MT_gpencil_append_active_material(Menu):
bl_label = "Append Active Material to Object"
def draw(self, context):
layout = self.layout
gpencil_material_menu_items(context, layout, True)
class VIEW3D_MT_gpencil_append_all_materials(Menu):
bl_label = "Append All Materials to Object"
def draw(self, context):
layout = self.layout
gpencil_material_menu_items(context, layout, False)
class VIEW3D_MT_edit_gpencil(Menu):
@ -6210,10 +6258,7 @@ class VIEW3D_PT_overlay_geometry(Panel):
sub.prop(overlay, "wireframe_opacity", text="Opacity")
row = col.row(align=True)
if context.mode not in {
'EDIT_ARMATURE', 'POSE', 'OBJECT',
'PAINT_GPENCIL', 'VERTEX_GPENCIL', 'WEIGHT_GPENCIL', 'SCULPT_GPENCIL', 'EDIT_GPENCIL',
}:
if context.mode != 'OBJECT':
row.prop(overlay, "show_fade_inactive", text="")
sub = row.row()
sub.active = overlay.show_fade_inactive
@ -7664,7 +7709,10 @@ classes = (
VIEW3D_MT_weight_gpencil,
VIEW3D_MT_gpencil_animation,
VIEW3D_MT_gpencil_simplify,
VIEW3D_MT_gpencil_copy_layer,
VIEW3D_MT_gpencil_append_active_layer,
VIEW3D_MT_gpencil_append_all_layers,
VIEW3D_MT_gpencil_append_active_material,
VIEW3D_MT_gpencil_append_all_materials,
VIEW3D_MT_gpencil_autoweights,
VIEW3D_MT_gpencil_edit_context_menu,
VIEW3D_MT_edit_curve,

View File

@ -1473,6 +1473,9 @@ class VIEW3D_PT_tools_grease_pencil_brush_advanced(View3DPanel, Panel):
row.prop(gp_settings, "extend_stroke_factor")
row.prop(gp_settings, "show_fill_extend", text="", icon='GRID')
col.separator()
col.prop(gp_settings, "fill_leak", text="Leak Size")
col.separator()
col.prop(gp_settings, "fill_simplify_level", text="Simplify")
if gp_settings.fill_draw_mode != 'STROKE':

View File

@ -488,6 +488,7 @@ geometry_node_categories = [
NodeItem("GeometryNodeAttributeClamp"),
NodeItem("GeometryNodeAttributeCompare"),
NodeItem("GeometryNodeAttributeConvert"),
NodeItem("GeometryNodeAttributeCurveMap"),
NodeItem("GeometryNodeAttributeFill"),
NodeItem("GeometryNodeAttributeMix"),
NodeItem("GeometryNodeAttributeProximity"),
@ -505,6 +506,10 @@ geometry_node_categories = [
NodeItem("ShaderNodeSeparateRGB"),
NodeItem("ShaderNodeCombineRGB"),
]),
GeometryNodeCategory("GEO_CURVE", "Curve", items=[
NodeItem("GeometryNodeCurveToMesh"),
NodeItem("GeometryNodeCurveResample"),
]),
GeometryNodeCategory("GEO_GEOMETRY", "Geometry", items=[
NodeItem("GeometryNodeBoundBox"),
NodeItem("GeometryNodeTransform"),

View File

@ -1,5 +1,4 @@
import bpy
import bgl
import blf
import gpu
from gpu_extras.batch import batch_for_shader
@ -17,16 +16,16 @@ def draw_callback_px(self, context):
# 50% alpha, 2 pixel width line
shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR')
bgl.glEnable(bgl.GL_BLEND)
bgl.glLineWidth(2)
gpu.state.blend_set('ALPHA')
gpu.state.line_width_set(2.0)
batch = batch_for_shader(shader, 'LINE_STRIP', {"pos": self.mouse_path})
shader.bind()
shader.uniform_float("color", (0.0, 0.0, 0.0, 0.5))
batch.draw(shader)
# restore opengl defaults
bgl.glLineWidth(1)
bgl.glDisable(bgl.GL_BLEND)
gpu.state.line_width_set(1.0)
gpu.state.blend_set('NONE')
class ModalDrawOperator(bpy.types.Operator):

View File

@ -140,7 +140,7 @@ void BKE_pose_channel_free_bbone_cache(struct bPoseChannel_Runtime *runtime);
void BKE_pose_channels_free(struct bPose *pose);
void BKE_pose_channels_free_ex(struct bPose *pose, bool do_id_user);
void BKE_pose_channels_hash_make(struct bPose *pose);
void BKE_pose_channels_hash_ensure(struct bPose *pose);
void BKE_pose_channels_hash_free(struct bPose *pose);
void BKE_pose_channels_remove(struct Object *ob,
@ -161,7 +161,7 @@ void BKE_pose_channel_session_uuid_generate(struct bPoseChannel *pchan);
struct bPoseChannel *BKE_pose_channel_find_name(const struct bPose *pose, const char *name);
struct bPoseChannel *BKE_pose_channel_active(struct Object *ob);
struct bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob);
struct bPoseChannel *BKE_pose_channel_verify(struct bPose *pose, const char *name);
struct bPoseChannel *BKE_pose_channel_ensure(struct bPose *pose, const char *name);
struct bPoseChannel *BKE_pose_channel_get_mirrored(const struct bPose *pose, const char *name);
void BKE_pose_check_uuids_unique_and_report(const struct bPose *pose);

View File

@ -14,6 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#pragma once
#include "BLI_array.hh"
#include "BLI_color.hh"
#include "BLI_float2.hh"
@ -130,6 +132,48 @@ inline Color4f mix3(const float3 &weights, const Color4f &v0, const Color4f &v1,
/** \} */
/* -------------------------------------------------------------------- */
/** \name Mix two values of the same type.
*
* This is just basic linear interpolation.
* \{ */
template<typename T> T mix2(const float factor, const T &a, const T &b);
template<> inline bool mix2(const float factor, const bool &a, const bool &b)
{
return ((1.0f - factor) * a + factor * b) >= 0.5f;
}
template<> inline int mix2(const float factor, const int &a, const int &b)
{
return static_cast<int>((1.0f - factor) * a + factor * b);
}
template<> inline float mix2(const float factor, const float &a, const float &b)
{
return (1.0f - factor) * a + factor * b;
}
template<> inline float2 mix2(const float factor, const float2 &a, const float2 &b)
{
return float2::interpolate(a, b, factor);
}
template<> inline float3 mix2(const float factor, const float3 &a, const float3 &b)
{
return float3::interpolate(a, b, factor);
}
template<> inline Color4f mix2(const float factor, const Color4f &a, const Color4f &b)
{
Color4f result;
interp_v4_v4v4(result, a, b, factor);
return result;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Mix a dynamic amount of values with weights for many elements.
*

View File

@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 0
#define BLENDER_FILE_SUBVERSION 1
/* 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

@ -36,25 +36,13 @@ typedef enum GeometryComponentType {
GEO_COMPONENT_TYPE_POINT_CLOUD = 1,
GEO_COMPONENT_TYPE_INSTANCES = 2,
GEO_COMPONENT_TYPE_VOLUME = 3,
GEO_COMPONENT_TYPE_CURVE = 4,
} GeometryComponentType;
void BKE_geometry_set_free(struct GeometrySet *geometry_set);
bool BKE_geometry_set_has_instances(const struct GeometrySet *geometry_set);
typedef enum InstancedDataType {
INSTANCE_DATA_TYPE_OBJECT = 0,
INSTANCE_DATA_TYPE_COLLECTION = 1,
} InstancedDataType;
typedef struct InstancedData {
InstancedDataType type;
union {
struct Object *object;
struct Collection *collection;
} data;
} InstancedData;
#ifdef __cplusplus
}
#endif

View File

@ -30,6 +30,7 @@
#include "BLI_map.hh"
#include "BLI_set.hh"
#include "BLI_user_counter.hh"
#include "BLI_vector_set.hh"
#include "BKE_attribute_access.hh"
#include "BKE_geometry_set.h"
@ -39,6 +40,7 @@ struct Mesh;
struct Object;
struct PointCloud;
struct Volume;
class CurveEval;
enum class GeometryOwnershipType {
/* The geometry is owned. This implies that it can be changed. */
@ -363,18 +365,25 @@ struct GeometrySet {
Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
static GeometrySet create_with_pointcloud(
PointCloud *pointcloud, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
static GeometrySet create_with_curve(
CurveEval *curve, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
/* Utility methods for access. */
bool has_mesh() const;
bool has_pointcloud() const;
bool has_instances() const;
bool has_volume() const;
bool has_curve() const;
const Mesh *get_mesh_for_read() const;
const PointCloud *get_pointcloud_for_read() const;
const Volume *get_volume_for_read() const;
const CurveEval *get_curve_for_read() const;
Mesh *get_mesh_for_write();
PointCloud *get_pointcloud_for_write();
Volume *get_volume_for_write();
CurveEval *get_curve_for_write();
/* Utility methods for replacement. */
void replace_mesh(Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
@ -382,6 +391,8 @@ struct GeometrySet {
GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
void replace_volume(Volume *volume,
GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
void replace_curve(CurveEval *curve,
GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
};
/** A geometry component that can store a mesh. */
@ -463,12 +474,113 @@ class PointCloudComponent : public GeometryComponent {
const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
};
/** A geometry component that stores curve data, in other words, a group of splines. */
class CurveComponent : public GeometryComponent {
private:
CurveEval *curve_ = nullptr;
GeometryOwnershipType ownership_ = GeometryOwnershipType::Owned;
public:
CurveComponent();
~CurveComponent();
GeometryComponent *copy() const override;
void clear();
bool has_curve() const;
void replace(CurveEval *curve, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
CurveEval *release();
const CurveEval *get_for_read() const;
CurveEval *get_for_write();
int attribute_domain_size(const AttributeDomain domain) const final;
bool is_empty() const final;
bool owns_direct_data() const override;
void ensure_owns_direct_data() override;
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_CURVE;
private:
const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
};
class InstanceReference {
public:
enum class Type {
/**
* An empty instance. This allows an `InstanceReference` to be default constructed without
* being in an invalid state. There might also be other use cases that we haven't explored much
* yet (such as changing the instance later on, and "disabling" some instances).
*/
None,
Object,
Collection,
};
private:
Type type_ = Type::None;
/** Depending on the type this is either null, an Object or Collection pointer. */
void *data_ = nullptr;
public:
InstanceReference() = default;
InstanceReference(Object &object) : type_(Type::Object), data_(&object)
{
}
InstanceReference(Collection &collection) : type_(Type::Collection), data_(&collection)
{
}
Type type() const
{
return type_;
}
Object &object() const
{
BLI_assert(type_ == Type::Object);
return *(Object *)data_;
}
Collection &collection() const
{
BLI_assert(type_ == Type::Collection);
return *(Collection *)data_;
}
uint64_t hash() const
{
return blender::get_default_hash(data_);
}
friend bool operator==(const InstanceReference &a, const InstanceReference &b)
{
return a.data_ == b.data_;
}
};
/** A geometry component that stores instances. */
class InstancesComponent : public GeometryComponent {
private:
blender::Vector<blender::float4x4> transforms_;
blender::Vector<int> ids_;
blender::Vector<InstancedData> instanced_data_;
/**
* Indexed set containing information about the data that is instanced.
* Actual instances store an index ("handle") into this set.
*/
blender::VectorSet<InstanceReference> references_;
/** Index into `references_`. Determines what data is instanced. */
blender::Vector<int> instance_reference_handles_;
/** Transformation of the instances. */
blender::Vector<blender::float4x4> instance_transforms_;
/**
* IDs of the instances. They are used for consistency over multiple frames for things like
* motion blur.
*/
blender::Vector<int> instance_ids_;
/* These almost unique ids are generated based on `ids_`, which might not contain unique ids at
* all. They are *almost* unique, because under certain very unlikely circumstances, they are not
@ -483,14 +595,22 @@ class InstancesComponent : public GeometryComponent {
GeometryComponent *copy() const override;
void clear();
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::float4x4> transforms() const;
blender::Span<int> ids() const;
blender::MutableSpan<blender::float4x4> transforms();
void reserve(int min_capacity);
void resize(int capacity);
int add_reference(InstanceReference reference);
void add_instance(int instance_handle, const blender::float4x4 &transform, const int id = -1);
blender::Span<InstanceReference> references() const;
blender::Span<int> instance_reference_handles() const;
blender::MutableSpan<int> instance_reference_handles();
blender::MutableSpan<blender::float4x4> instance_transforms();
blender::Span<blender::float4x4> instance_transforms() const;
blender::MutableSpan<int> instance_ids();
blender::Span<int> instance_ids() const;
int instances_amount() const;
blender::Span<int> almost_unique_ids() const;

View File

@ -85,10 +85,12 @@ bool BKE_lib_override_library_resync(struct Main *bmain,
struct ID *id_root,
struct Collection *override_resync_residual_storage,
const bool do_hierarchy_enforce,
const bool do_post_process);
const bool do_post_process,
struct ReportList *reports);
void BKE_lib_override_library_main_resync(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
struct ViewLayer *view_layer,
struct ReportList *reports);
void BKE_lib_override_library_delete(struct Main *bmain, struct ID *id_root);

View File

@ -70,12 +70,15 @@ enum {
/** That ID is used as library override's reference by its owner. */
IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE = (1 << 5),
/** That ID pointer is not overridable. */
IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE = (1 << 6),
/**
* Indicates that this is an internal runtime ID pointer, like e.g. `ID.newid` or `ID.original`.
* \note Those should be ignored in most cases, and won't be processed/generated anyway unless
* `IDWALK_DO_INTERNAL_RUNTIME_POINTERS` option is enabled.
*/
IDWALK_CB_INTERNAL = (1 << 6),
IDWALK_CB_INTERNAL = (1 << 7),
/**
* This ID usage is fully refcounted.

View File

@ -577,9 +577,9 @@ void BKE_mesh_polygons_flip(struct MPoly *mpoly,
struct CustomData *ldata,
int totpoly);
/* merge verts */
/* Enum for merge_mode of CDDM_merge_verts.
* Refer to mesh.c for details. */
/* Merge verts. */
/* Enum for merge_mode of #BKE_mesh_merge_verts.
* Refer to mesh_merge.c for details. */
enum {
MESH_MERGE_VERTS_DUMP_IF_MAPPED,
MESH_MERGE_VERTS_DUMP_IF_EQUAL,

View File

@ -446,8 +446,8 @@ bool BKE_modifier_is_preview(struct ModifierData *md);
void BKE_modifiers_foreach_ID_link(struct Object *ob, IDWalkFunc walk, void *userData);
void BKE_modifiers_foreach_tex_link(struct Object *ob, TexWalkFunc walk, void *userData);
struct ModifierData *BKE_modifiers_findby_type(struct Object *ob, ModifierType type);
struct ModifierData *BKE_modifiers_findby_name(struct Object *ob, const char *name);
struct ModifierData *BKE_modifiers_findby_type(const struct Object *ob, ModifierType type);
struct ModifierData *BKE_modifiers_findby_name(const struct Object *ob, const char *name);
void BKE_modifiers_clear_errors(struct Object *ob);
int BKE_modifiers_get_cage_index(const struct Scene *scene,
struct Object *ob,

View File

@ -58,7 +58,14 @@ struct NlaTrack *BKE_nlatrack_copy(struct Main *bmain,
struct NlaTrack *nlt,
const bool use_same_actions,
const int flag);
void BKE_nla_tracks_copy(struct Main *bmain, ListBase *dst, ListBase *src, const int flag);
void BKE_nla_tracks_copy(struct Main *bmain, ListBase *dst, const ListBase *src, const int flag);
/* Copy NLA tracks from #adt_source to #adt_dest, and update the active track/strip pointers to
* point at those copies. */
void BKE_nla_tracks_copy_from_adt(struct Main *bmain,
struct AnimData *adt_dest,
const struct AnimData *adt_source,
int flag);
struct NlaTrack *BKE_nlatrack_add(struct AnimData *adt,
struct NlaTrack *prev,

View File

@ -410,6 +410,9 @@ typedef struct bNodeTreeType {
void (*node_add_init)(struct bNodeTree *ntree, struct bNode *bnode);
/* Check if the socket type is valid for this tree type. */
bool (*valid_socket_type)(enum eNodeSocketDatatype socket_type, struct bNodeTreeType *ntreetype);
/* RNA integration */
ExtensionRNA rna_ext;
} bNodeTreeType;
@ -1415,6 +1418,9 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_BOUNDING_BOX 1042
#define GEO_NODE_SWITCH 1043
#define GEO_NODE_ATTRIBUTE_TRANSFER 1044
#define GEO_NODE_CURVE_TO_MESH 1045
#define GEO_NODE_ATTRIBUTE_CURVE_MAP 1046
#define GEO_NODE_CURVE_RESAMPLE 1047
/** \} */

View File

@ -374,6 +374,7 @@ struct MovieClip *BKE_object_movieclip_get(struct Scene *scene,
void BKE_object_runtime_reset(struct Object *object);
void BKE_object_runtime_reset_on_copy(struct Object *object, const int flag);
void BKE_object_runtime_free_data(struct Object *object);
void BKE_object_batch_cache_dirty_tag(struct Object *ob);

View File

@ -1,153 +0,0 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#pragma once
/** \file
* \ingroup bke
*
* A PersistentDataHandle is a weak reference to some data in a Blender file. The handle itself is
* just a number. A PersistentDataHandleMap is used to convert between handles and the actual data.
*/
#include "BLI_map.hh"
#include "DNA_ID.h"
struct Collection;
struct Object;
namespace blender::bke {
class PersistentDataHandleMap;
class PersistentDataHandle {
private:
/* Negative values indicate that the handle is "empty". */
int32_t handle_;
friend PersistentDataHandleMap;
protected:
PersistentDataHandle(int handle) : handle_(handle)
{
}
public:
PersistentDataHandle() : handle_(-1)
{
}
friend bool operator==(const PersistentDataHandle &a, const PersistentDataHandle &b)
{
return a.handle_ == b.handle_;
}
friend bool operator!=(const PersistentDataHandle &a, const PersistentDataHandle &b)
{
return !(a == b);
}
friend std::ostream &operator<<(std::ostream &stream, const PersistentDataHandle &a)
{
stream << a.handle_;
return stream;
}
uint64_t hash() const
{
return static_cast<uint64_t>(handle_);
}
};
class PersistentIDHandle : public PersistentDataHandle {
friend PersistentDataHandleMap;
using PersistentDataHandle::PersistentDataHandle;
};
class PersistentObjectHandle : public PersistentIDHandle {
friend PersistentDataHandleMap;
using PersistentIDHandle::PersistentIDHandle;
};
class PersistentCollectionHandle : public PersistentIDHandle {
friend PersistentDataHandleMap;
using PersistentIDHandle::PersistentIDHandle;
};
class PersistentDataHandleMap {
private:
Map<int32_t, ID *> id_by_handle_;
Map<ID *, int32_t> handle_by_id_;
public:
void add(int32_t handle, ID &id)
{
BLI_assert(handle >= 0);
handle_by_id_.add(&id, handle);
id_by_handle_.add(handle, &id);
}
PersistentIDHandle lookup(ID *id) const
{
const int handle = handle_by_id_.lookup_default(id, -1);
return PersistentIDHandle(handle);
}
PersistentObjectHandle lookup(Object *object) const
{
const int handle = handle_by_id_.lookup_default((ID *)object, -1);
return PersistentObjectHandle(handle);
}
PersistentCollectionHandle lookup(Collection *collection) const
{
const int handle = handle_by_id_.lookup_default((ID *)collection, -1);
return PersistentCollectionHandle(handle);
}
ID *lookup(const PersistentIDHandle &handle) const
{
ID *id = id_by_handle_.lookup_default(handle.handle_, nullptr);
return id;
}
Object *lookup(const PersistentObjectHandle &handle) const
{
ID *id = this->lookup((const PersistentIDHandle &)handle);
if (id == nullptr) {
return nullptr;
}
if (GS(id->name) != ID_OB) {
return nullptr;
}
return (Object *)id;
}
Collection *lookup(const PersistentCollectionHandle &handle) const
{
ID *id = this->lookup((const PersistentIDHandle &)handle);
if (id == nullptr) {
return nullptr;
}
if (GS(id->name) != ID_GR) {
return nullptr;
}
return (Collection *)id;
}
};
} // namespace blender::bke

View File

@ -0,0 +1,485 @@
/*
* 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.
*/
#pragma once
/** \file
* \ingroup bke
*/
#include <mutex>
#include "FN_generic_virtual_array.hh"
#include "BLI_float3.hh"
#include "BLI_float4x4.hh"
#include "BLI_vector.hh"
#include "BKE_attribute_math.hh"
struct Curve;
class Spline;
using SplinePtr = std::unique_ptr<Spline>;
/**
* A spline is an abstraction of a single branch-less curve section, its evaluation methods,
* and data. The spline data itself is just control points and a set of attributes by the set
* of "evaluated" data is often used instead.
*
* Any derived class of Spline has to manage two things:
* 1. Interpolating arbitrary attribute data from the control points to evaluated points.
* 2. Evaluating the positions based on the stored control point data.
*
* Beyond that, everything is the base class's responsibility, with minor exceptions. Further
* evaluation happens in a layer on top of the evaluated points generated by the derived types.
*
* There are a few methods to evaluate a spline:
* 1. #evaluated_positions and #interpolate_to_evaluated_points give data at the initial
* evaluated points, depending on the resolution.
* 2. #lookup_evaluated_factor and #lookup_evaluated_factor are meant for one-off lookups
* along the length of a curve.
*
* Commonly used evaluated data is stored in caches on the spline itself so that operations on
* splines don't need to worry about taking ownership of evaluated data when they don't need to.
*/
class Spline {
public:
enum class Type {
Bezier,
NURBS,
Poly,
};
protected:
Type type_;
bool is_cyclic_ = false;
public:
enum NormalCalculationMode {
ZUp,
Minimum,
Tangent,
};
/* Only #Zup is supported at the moment. */
NormalCalculationMode normal_mode;
protected:
/** Direction of the spline at each evaluated point. */
mutable blender::Vector<blender::float3> evaluated_tangents_cache_;
mutable std::mutex tangent_cache_mutex_;
mutable bool tangent_cache_dirty_ = true;
/** Normal direction vectors for each evaluated point. */
mutable blender::Vector<blender::float3> evaluated_normals_cache_;
mutable std::mutex normal_cache_mutex_;
mutable bool normal_cache_dirty_ = true;
/** Accumulated lengths along the evaluated points. */
mutable blender::Vector<float> evaluated_lengths_cache_;
mutable std::mutex length_cache_mutex_;
mutable bool length_cache_dirty_ = true;
public:
virtual ~Spline() = default;
Spline(const Type type) : type_(type)
{
}
Spline(Spline &other)
: type_(other.type_), is_cyclic_(other.is_cyclic_), normal_mode(other.normal_mode)
{
}
virtual SplinePtr copy() const = 0;
Spline::Type type() const;
/** Return the number of control points. */
virtual int size() const = 0;
int segments_size() const;
bool is_cyclic() const;
void set_cyclic(const bool value);
virtual void resize(const int size) = 0;
virtual blender::MutableSpan<blender::float3> positions() = 0;
virtual blender::Span<blender::float3> positions() const = 0;
virtual blender::MutableSpan<float> radii() = 0;
virtual blender::Span<float> radii() const = 0;
virtual blender::MutableSpan<float> tilts() = 0;
virtual blender::Span<float> tilts() const = 0;
virtual void translate(const blender::float3 &translation);
virtual void transform(const blender::float4x4 &matrix);
/**
* Mark all caches for re-computation. This must be called after any operation that would
* change the generated positions, tangents, normals, mapping, etc. of the evaluated points.
*/
virtual void mark_cache_invalid() = 0;
virtual int evaluated_points_size() const = 0;
int evaluated_edges_size() const;
float length() const;
virtual blender::Span<blender::float3> evaluated_positions() const = 0;
blender::Span<float> evaluated_lengths() const;
blender::Span<blender::float3> evaluated_tangents() const;
blender::Span<blender::float3> evaluated_normals() const;
void bounds_min_max(blender::float3 &min, blender::float3 &max, const bool use_evaluated) const;
struct LookupResult {
/**
* The index of the evaluated point before the result location. In other words, the index of
* the edge that the result lies on. If the sampled factor/length is the very end of the
* spline, this will be the second to last index, if it's the very beginning, this will be 0.
*/
int evaluated_index;
/**
* The index of the evaluated point after the result location, accounting for wrapping when
* the spline is cyclic. If the sampled factor/length is the very end of the spline, this will
* be the last index (#evaluated_points_size - 1).
*/
int next_evaluated_index;
/**
* The portion of the way from the evaluated point at #evaluated_index to the next point.
* If the sampled factor/length is the very end of the spline, this will be the 1.0f
*/
float factor;
};
LookupResult lookup_evaluated_factor(const float factor) const;
LookupResult lookup_evaluated_length(const float length) const;
blender::Array<float> sample_uniform_index_factors(const int samples_size) const;
LookupResult lookup_data_from_index_factor(const float index_factor) const;
/**
* Interpolate a virtual array of data with the size of the number of control points to the
* evaluated points. For poly splines, the lifetime of the returned virtual array must not
* exceed the lifetime of the input data.
*/
virtual blender::fn::GVArrayPtr interpolate_to_evaluated_points(
const blender::fn::GVArray &source_data) const = 0;
protected:
virtual void correct_end_tangents() const = 0;
};
/**
* A Bézier spline is made up of a many curve segments, possibly achieving continuity of curvature
* by constraining the alignment of curve handles. Evaluation stores the positions and a map of
* factors and indices in a list of floats, which is then used to interpolate any other data.
*/
class BezierSpline final : public Spline {
public:
enum class HandleType {
/** The handle can be moved anywhere, and doesn't influence the point's other handle. */
Free,
/** The location is automatically calculated to be smooth. */
Auto,
/** The location is calculated to point to the next/previous control point. */
Vector,
/** The location is constrained to point in the opposite direction as the other handle. */
Align,
};
private:
blender::Vector<HandleType> handle_types_left_;
blender::Vector<blender::float3> handle_positions_left_;
blender::Vector<blender::float3> positions_;
blender::Vector<HandleType> handle_types_right_;
blender::Vector<blender::float3> handle_positions_right_;
blender::Vector<float> radii_;
blender::Vector<float> tilts_;
int resolution_;
/** Start index in evaluated points array for every control point. */
mutable blender::Vector<int> offset_cache_;
mutable std::mutex offset_cache_mutex_;
mutable bool offset_cache_dirty_ = true;
/** Cache of evaluated positions. */
mutable blender::Vector<blender::float3> evaluated_position_cache_;
mutable std::mutex position_cache_mutex_;
mutable bool position_cache_dirty_ = true;
/** Cache of "index factors" based calculated from the evaluated positions. */
mutable blender::Vector<float> evaluated_mapping_cache_;
mutable std::mutex mapping_cache_mutex_;
mutable bool mapping_cache_dirty_ = true;
public:
virtual SplinePtr copy() const final;
BezierSpline() : Spline(Type::Bezier)
{
}
BezierSpline(const BezierSpline &other)
: Spline((Spline &)other),
handle_types_left_(other.handle_types_left_),
handle_positions_left_(other.handle_positions_left_),
positions_(other.positions_),
handle_types_right_(other.handle_types_right_),
handle_positions_right_(other.handle_positions_right_),
radii_(other.radii_),
tilts_(other.tilts_),
resolution_(other.resolution_)
{
}
int size() const final;
int resolution() const;
void set_resolution(const int value);
void add_point(const blender::float3 position,
const HandleType handle_type_start,
const blender::float3 handle_position_start,
const HandleType handle_type_end,
const blender::float3 handle_position_end,
const float radius,
const float tilt);
void resize(const int size) final;
blender::MutableSpan<blender::float3> positions() final;
blender::Span<blender::float3> positions() const final;
blender::MutableSpan<float> radii() final;
blender::Span<float> radii() const final;
blender::MutableSpan<float> tilts() final;
blender::Span<float> tilts() const final;
blender::Span<HandleType> handle_types_left() const;
blender::MutableSpan<HandleType> handle_types_left();
blender::Span<blender::float3> handle_positions_left() const;
blender::MutableSpan<blender::float3> handle_positions_left();
blender::Span<HandleType> handle_types_right() const;
blender::MutableSpan<HandleType> handle_types_right();
blender::Span<blender::float3> handle_positions_right() const;
blender::MutableSpan<blender::float3> handle_positions_right();
void translate(const blender::float3 &translation) override;
void transform(const blender::float4x4 &matrix) override;
bool point_is_sharp(const int index) const;
void mark_cache_invalid() final;
int evaluated_points_size() const final;
blender::Span<int> control_point_offsets() const;
blender::Span<float> evaluated_mappings() const;
blender::Span<blender::float3> evaluated_positions() const final;
struct InterpolationData {
int control_point_index;
int next_control_point_index;
/**
* Linear interpolation weight between the two indices, from 0 to 1.
* Higher means next control point.
*/
float factor;
};
InterpolationData interpolation_data_from_index_factor(const float index_factor) const;
virtual blender::fn::GVArrayPtr interpolate_to_evaluated_points(
const blender::fn::GVArray &source_data) const override;
private:
void correct_end_tangents() const final;
bool segment_is_vector(const int start_index) const;
void evaluate_bezier_segment(const int index,
const int next_index,
blender::MutableSpan<blender::float3> positions) const;
blender::Array<int> evaluated_point_offsets() const;
};
/**
* Data for Non-Uniform Rational B-Splines. The mapping from control points to evaluated points is
* influenced by a vector of knots, weights for each point, and the order of the spline. Every
* mapping of data to evaluated points is handled the same way, but the positions are cached in
* the spline.
*/
class NURBSpline final : public Spline {
public:
enum class KnotsMode {
Normal,
EndPoint,
Bezier,
};
KnotsMode knots_mode;
struct BasisCache {
/** The influence at each control point `i + #start_index`. */
blender::Vector<float> weights;
/**
* An offset for the start of #weights: the first control point index with a non-zero weight.
*/
int start_index;
};
private:
blender::Vector<blender::float3> positions_;
blender::Vector<float> radii_;
blender::Vector<float> tilts_;
blender::Vector<float> weights_;
int resolution_;
/**
* Defines the number of nearby control points that influence a given evaluated point. Higher
* orders give smoother results. The number of control points must be greater than or equal to
* this value.
*/
uint8_t order_;
/**
* Determines where and how the control points affect the evaluated points. The length should
* always be the value returned by #knots_size(), and each value should be greater than or equal
* to the previous. Only invalidated when a point is added or removed.
*/
mutable blender::Vector<float> knots_;
mutable std::mutex knots_mutex_;
mutable bool knots_dirty_ = true;
/** Cache of control point influences on each evaluated point. */
mutable blender::Vector<BasisCache> basis_cache_;
mutable std::mutex basis_cache_mutex_;
mutable bool basis_cache_dirty_ = true;
/**
* Cache of position data calculated from the basis cache. Though it is interpolated
* in the same way as any other attribute, it is stored to save unnecessary recalculation.
*/
mutable blender::Vector<blender::float3> evaluated_position_cache_;
mutable std::mutex position_cache_mutex_;
mutable bool position_cache_dirty_ = true;
public:
SplinePtr copy() const final;
NURBSpline() : Spline(Type::NURBS)
{
}
NURBSpline(const NURBSpline &other)
: Spline((Spline &)other),
knots_mode(other.knots_mode),
positions_(other.positions_),
radii_(other.radii_),
tilts_(other.tilts_),
weights_(other.weights_),
resolution_(other.resolution_),
order_(other.order_)
{
}
int size() const final;
int resolution() const;
void set_resolution(const int value);
uint8_t order() const;
void set_order(const uint8_t value);
void add_point(const blender::float3 position,
const float radius,
const float tilt,
const float weight);
bool check_valid_size_and_order() const;
int knots_size() const;
void resize(const int size) final;
blender::MutableSpan<blender::float3> positions() final;
blender::Span<blender::float3> positions() const final;
blender::MutableSpan<float> radii() final;
blender::Span<float> radii() const final;
blender::MutableSpan<float> tilts() final;
blender::Span<float> tilts() const final;
blender::Span<float> knots() const;
blender::MutableSpan<float> weights();
blender::Span<float> weights() const;
void mark_cache_invalid() final;
int evaluated_points_size() const final;
blender::Span<blender::float3> evaluated_positions() const final;
blender::fn::GVArrayPtr interpolate_to_evaluated_points(
const blender::fn::GVArray &source_data) const final;
protected:
void correct_end_tangents() const final;
void calculate_knots() const;
void calculate_basis_cache() const;
};
/**
* A Poly spline is like a bezier spline with a resolution of one. The main reason to distinguish
* the two is for reduced complexity and increased performance, since interpolating data to control
* points does not change it.
*/
class PolySpline final : public Spline {
public:
blender::Vector<blender::float3> positions_;
blender::Vector<float> radii_;
blender::Vector<float> tilts_;
private:
public:
SplinePtr copy() const final;
PolySpline() : Spline(Type::Poly)
{
}
PolySpline(const PolySpline &other)
: Spline((Spline &)other),
positions_(other.positions_),
radii_(other.radii_),
tilts_(other.tilts_)
{
}
int size() const final;
void add_point(const blender::float3 position, const float radius, const float tilt);
void resize(const int size) final;
blender::MutableSpan<blender::float3> positions() final;
blender::Span<blender::float3> positions() const final;
blender::MutableSpan<float> radii() final;
blender::Span<float> radii() const final;
blender::MutableSpan<float> tilts() final;
blender::Span<float> tilts() const final;
void mark_cache_invalid() final;
int evaluated_points_size() const final;
blender::Span<blender::float3> evaluated_positions() const final;
blender::fn::GVArrayPtr interpolate_to_evaluated_points(
const blender::fn::GVArray &source_data) const final;
protected:
void correct_end_tangents() const final;
};
/**
* A #CurveEval corresponds to the #Curve object data. The name is different for clarity, since
* more of the data is stored in the splines, but also just to be different than the name in DNA.
*/
class CurveEval {
public:
blender::Vector<SplinePtr> splines;
CurveEval *copy();
void translate(const blender::float3 &translation);
void transform(const blender::float4x4 &matrix);
void bounds_min_max(blender::float3 &min, blender::float3 &max, const bool use_evaluated) const;
};
std::unique_ptr<CurveEval> curve_eval_from_dna_curve(const Curve &curve);

View File

@ -112,6 +112,7 @@ set(SRC
intern/curve_convert.c
intern/curve_decimate.c
intern/curve_deform.c
intern/curve_eval.cc
intern/curveprofile.c
intern/customdata.c
intern/customdata_file.c
@ -133,6 +134,7 @@ set(SRC
intern/fmodifier.c
intern/font.c
intern/freestyle.c
intern/geometry_component_curve.cc
intern/geometry_component_instances.cc
intern/geometry_component_mesh.cc
intern/geometry_component_pointcloud.cc
@ -241,6 +243,10 @@ set(SRC
intern/softbody.c
intern/sound.c
intern/speaker.c
intern/spline_base.cc
intern/spline_bezier.cc
intern/spline_nurbs.cc
intern/spline_poly.cc
intern/studiolight.c
intern/subdiv.c
intern/subdiv_ccg.c
@ -322,6 +328,7 @@ set(SRC
BKE_customdata_file.h
BKE_data_transfer.h
BKE_deform.h
BKE_spline.hh
BKE_displist.h
BKE_displist_tangent.h
BKE_duplilist.h
@ -399,7 +406,6 @@ set(SRC
BKE_paint.h
BKE_particle.h
BKE_pbvh.h
BKE_persistent_data_handle.hh
BKE_pointcache.h
BKE_pointcloud.h
BKE_preferences.h
@ -585,10 +591,6 @@ if(WITH_CODEC_FFMPEG)
${FFMPEG_LIBRARIES}
)
add_definitions(-DWITH_FFMPEG)
remove_strict_c_flags_file(
intern/writeffmpeg.c
)
endif()
if(WITH_PYTHON)

View File

@ -1859,9 +1859,11 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
BKE_id_free(nullptr, mesh_orco);
}
/* Ensure normals calculation below is correct. */
BLI_assert((mesh_input->flag & ME_AUTOSMOOTH) == (mesh_final->flag & ME_AUTOSMOOTH));
BLI_assert(mesh_input->smoothresh == mesh_final->smoothresh);
/* Ensure normals calculation below is correct (normal settings have transferred properly).
* However, nodes modifiers might create meshes from scratch or transfer meshes from other
* objects with different settings, and in general it doesn't make sense to guarantee that
* the settings are the same as the original mesh. If necessary, this could become a modifier
* type flag. */
BLI_assert(mesh_input->smoothresh == mesh_cage->smoothresh);
/* Compute normals. */

View File

@ -635,7 +635,7 @@ bPoseChannel *BKE_pose_channel_find_name(const bPose *pose, const char *name)
* \note Use with care, not on Armature poses but for temporal ones.
* \note (currently used for action constraints and in rebuild_pose).
*/
bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name)
bPoseChannel *BKE_pose_channel_ensure(bPose *pose, const char *name)
{
bPoseChannel *chan;
@ -815,7 +815,7 @@ void BKE_pose_copy_data_ex(bPose **dst,
*/
if (outPose->chanbase.first != outPose->chanbase.last) {
outPose->chanhash = NULL;
BKE_pose_channels_hash_make(outPose);
BKE_pose_channels_hash_ensure(outPose);
}
outPose->iksolver = src->iksolver;
@ -945,7 +945,7 @@ bool BKE_pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan)
* Removes the hash for quick lookup of channels, must
* be done when adding/removing channels.
*/
void BKE_pose_channels_hash_make(bPose *pose)
void BKE_pose_channels_hash_ensure(bPose *pose)
{
if (!pose->chanhash) {
bPoseChannel *pchan;
@ -1191,7 +1191,7 @@ void BKE_pose_free(bPose *pose)
* and ID-Props, used when duplicating bones in editmode.
* (unlike copy_pose_channel_data which only does posing-related stuff).
*
* \note use when copying bones in editmode (on returned value from #BKE_pose_channel_verify)
* \note use when copying bones in editmode (on returned value from #BKE_pose_channel_ensure)
*/
void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_from)
{
@ -1774,7 +1774,7 @@ void what_does_obaction(Object *ob,
* allocation and also will make lookup slower.
*/
if (pose->chanbase.first != pose->chanbase.last) {
BKE_pose_channels_hash_make(pose);
BKE_pose_channels_hash_ensure(pose);
}
if (pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
BKE_pose_update_constraint_flags(pose);

View File

@ -354,7 +354,7 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
}
/* duplicate NLA data */
BKE_nla_tracks_copy(bmain, &dadt->nla_tracks, &adt->nla_tracks, flag);
BKE_nla_tracks_copy_from_adt(bmain, dadt, adt, flag);
/* duplicate drivers (F-Curves) */
BKE_fcurves_copy(&dadt->drivers, &adt->drivers);

View File

@ -2444,7 +2444,7 @@ static void pose_proxy_sync(Object *ob, Object *from, int layer_protected)
static int rebuild_pose_bone(
bPose *pose, Bone *bone, bPoseChannel *parchan, int counter, Bone **r_last_visited_bone_p)
{
bPoseChannel *pchan = BKE_pose_channel_verify(pose, bone->name); /* verify checks and/or adds */
bPoseChannel *pchan = BKE_pose_channel_ensure(pose, bone->name); /* verify checks and/or adds */
pchan->bone = bone;
pchan->parent = parchan;
@ -2562,7 +2562,7 @@ void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm, const bool do_id_
/* and a check for garbage */
BKE_pose_channels_clear_with_null_bone(pose, do_id_user);
BKE_pose_channels_hash_make(pose);
BKE_pose_channels_hash_ensure(pose);
for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
/* Find the custom B-Bone handles. */

View File

@ -340,13 +340,22 @@ static int position_tail_on_spline(bSplineIKConstraint *ik_data,
float isect_1[3], isect_2[3];
/* Calculate the intersection point. */
isect_line_sphere_v3(prev_bp->vec, bp->vec, head_pos, sphere_radius, isect_1, isect_2);
int ret = isect_line_sphere_v3(prev_bp->vec, bp->vec, head_pos, sphere_radius, isect_1, isect_2);
/* Because of how `isect_line_sphere_v3` works, we know that `isect_1` contains the
* intersection point we want. And it will always intersect as we go from inside to outside
* of the sphere.
*/
copy_v3_v3(r_tail_pos, isect_1);
if (ret > 0) {
/* Because of how `isect_line_sphere_v3` works, we know that `isect_1` contains the
* intersection point we want. And it will always intersect as we go from inside to outside
* of the sphere.
*/
copy_v3_v3(r_tail_pos, isect_1);
}
else {
/* Couldn't find an intersection point. This means that the floating point
* values are too small and thus the intersection check fails.
* So assume that the distance is so small that tail_pos == head_pos.
*/
copy_v3_v3(r_tail_pos, head_pos);
}
cur_seg_idx = bp_idx - 2;
float prev_seg_len = 0;
@ -360,7 +369,7 @@ static int position_tail_on_spline(bSplineIKConstraint *ik_data,
}
/* Convert the point back into the 0-1 interpolation range. */
const float isect_seg_len = len_v3v3(prev_bp->vec, isect_1);
const float isect_seg_len = len_v3v3(prev_bp->vec, r_tail_pos);
const float frac = isect_seg_len / len_v3v3(prev_bp->vec, bp->vec);
*r_new_curve_pos = (prev_seg_len + isect_seg_len) / spline_len;
@ -380,7 +389,7 @@ static void splineik_evaluate_bone(
{
bSplineIKConstraint *ik_data = tree->ik_data;
if (pchan->bone->length == 0.0f) {
if (pchan->bone->length < FLT_EPSILON) {
/* Only move the bone position with zero length bones. */
float bone_pos[4], dir[3], rad;
BKE_where_on_path(ik_data->tar, state->curve_position, bone_pos, dir, NULL, &rad, NULL);
@ -516,6 +525,25 @@ static void splineik_evaluate_bone(
*/
cross_v3_v3v3(raxis, rmat[1], spline_vec);
/* Check if the old and new bone direction is parallel to each other.
* If they are, then 'raxis' should be near zero and we will have to get the rotation axis in
* some other way.
*/
float norm = normalize_v3(raxis);
if (norm < FLT_EPSILON) {
/* Can't use cross product! */
int order[3] = {0, 1, 2};
float tmp_axis[3];
zero_v3(tmp_axis);
axis_sort_v3(spline_vec, order);
/* Use the second largest axis as the basis for the rotation axis. */
tmp_axis[order[1]] = 1.0f;
cross_v3_v3v3(raxis, tmp_axis, spline_vec);
}
rangle = dot_v3v3(rmat[1], spline_vec);
CLAMP(rangle, -1.0f, 1.0f);
rangle = acosf(rangle);

View File

@ -143,10 +143,8 @@ CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_
static int attribute_domain_priority(const AttributeDomain domain)
{
switch (domain) {
#if 0
case ATTR_DOMAIN_CURVE:
return 0;
#endif
case ATTR_DOMAIN_FACE:
return 1;
case ATTR_DOMAIN_EDGE:

View File

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

View File

@ -1043,6 +1043,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
brush->gpencil_settings->draw_smoothfac = 0.1f;
brush->gpencil_settings->draw_smoothlvl = 1;
brush->gpencil_settings->draw_subdivide = 1;
brush->gpencil_settings->dilate_pixels = 1;
brush->gpencil_settings->flag |= GP_BRUSH_FILL_SHOW_EXTENDLINES;

View File

@ -2836,7 +2836,7 @@ static void actcon_get_tarmat(struct Depsgraph *depsgraph,
* including rotation order, otherwise this fails. */
pchan = cob->pchan;
tchan = BKE_pose_channel_verify(&pose, pchan->name);
tchan = BKE_pose_channel_ensure(&pose, pchan->name);
tchan->rotmode = pchan->rotmode;
/* evaluate action using workob (it will only set the PoseChannel in question) */

View File

@ -0,0 +1,184 @@
/*
* 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.
*/
#include "BLI_array.hh"
#include "BLI_listbase.h"
#include "BLI_span.hh"
#include "DNA_curve_types.h"
#include "BKE_curve.h"
#include "BKE_spline.hh"
using blender::float3;
using blender::float4x4;
using blender::Span;
CurveEval *CurveEval::copy()
{
CurveEval *new_curve = new CurveEval();
for (SplinePtr &spline : this->splines) {
new_curve->splines.append(spline->copy());
}
return new_curve;
}
void CurveEval::translate(const float3 &translation)
{
for (SplinePtr &spline : this->splines) {
spline->translate(translation);
spline->mark_cache_invalid();
}
}
void CurveEval::transform(const float4x4 &matrix)
{
for (SplinePtr &spline : this->splines) {
spline->transform(matrix);
}
}
void CurveEval::bounds_min_max(float3 &min, float3 &max, const bool use_evaluated) const
{
for (const SplinePtr &spline : this->splines) {
spline->bounds_min_max(min, max, use_evaluated);
}
}
static BezierSpline::HandleType handle_type_from_dna_bezt(const eBezTriple_Handle dna_handle_type)
{
switch (dna_handle_type) {
case HD_FREE:
return BezierSpline::HandleType::Free;
case HD_AUTO:
return BezierSpline::HandleType::Auto;
case HD_VECT:
return BezierSpline::HandleType::Vector;
case HD_ALIGN:
return BezierSpline::HandleType::Align;
case HD_AUTO_ANIM:
return BezierSpline::HandleType::Auto;
case HD_ALIGN_DOUBLESIDE:
return BezierSpline::HandleType::Align;
}
BLI_assert_unreachable();
return BezierSpline::HandleType::Auto;
}
static Spline::NormalCalculationMode normal_mode_from_dna_curve(const int twist_mode)
{
switch (twist_mode) {
case CU_TWIST_Z_UP:
return Spline::NormalCalculationMode::ZUp;
case CU_TWIST_MINIMUM:
return Spline::NormalCalculationMode::Minimum;
case CU_TWIST_TANGENT:
return Spline::NormalCalculationMode::Tangent;
}
BLI_assert_unreachable();
return Spline::NormalCalculationMode::Minimum;
}
static NURBSpline::KnotsMode knots_mode_from_dna_nurb(const short flag)
{
switch (flag & (CU_NURB_ENDPOINT | CU_NURB_BEZIER)) {
case CU_NURB_ENDPOINT:
return NURBSpline::KnotsMode::EndPoint;
case CU_NURB_BEZIER:
return NURBSpline::KnotsMode::Bezier;
default:
return NURBSpline::KnotsMode::Normal;
}
BLI_assert_unreachable();
return NURBSpline::KnotsMode::Normal;
}
std::unique_ptr<CurveEval> curve_eval_from_dna_curve(const Curve &dna_curve)
{
std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
const ListBase *nurbs = BKE_curve_nurbs_get(&const_cast<Curve &>(dna_curve));
curve->splines.reserve(BLI_listbase_count(nurbs));
/* TODO: Optimize by reserving the correct points size. */
LISTBASE_FOREACH (const Nurb *, nurb, nurbs) {
switch (nurb->type) {
case CU_BEZIER: {
std::unique_ptr<BezierSpline> spline = std::make_unique<BezierSpline>();
spline->set_resolution(nurb->resolu);
spline->set_cyclic(nurb->flagu & CU_NURB_CYCLIC);
for (const BezTriple &bezt : Span(nurb->bezt, nurb->pntsu)) {
spline->add_point(bezt.vec[1],
handle_type_from_dna_bezt((eBezTriple_Handle)bezt.h1),
bezt.vec[0],
handle_type_from_dna_bezt((eBezTriple_Handle)bezt.h2),
bezt.vec[2],
bezt.radius,
bezt.tilt);
}
curve->splines.append(std::move(spline));
break;
}
case CU_NURBS: {
std::unique_ptr<NURBSpline> spline = std::make_unique<NURBSpline>();
spline->set_resolution(nurb->resolu);
spline->set_cyclic(nurb->flagu & CU_NURB_CYCLIC);
spline->set_order(nurb->orderu);
spline->knots_mode = knots_mode_from_dna_nurb(nurb->flagu);
for (const BPoint &bp : Span(nurb->bp, nurb->pntsu)) {
spline->add_point(bp.vec, bp.radius, bp.tilt, bp.vec[3]);
}
curve->splines.append(std::move(spline));
break;
}
case CU_POLY: {
std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
spline->set_cyclic(nurb->flagu & CU_NURB_CYCLIC);
for (const BPoint &bp : Span(nurb->bp, nurb->pntsu)) {
spline->add_point(bp.vec, bp.radius, bp.tilt);
}
curve->splines.append(std::move(spline));
break;
}
default: {
BLI_assert_unreachable();
break;
}
}
}
/* Note: Normal mode is stored separately in each spline to facilitate combining splines
* from multiple curve objects, where the value may be different. */
const Spline::NormalCalculationMode normal_mode = normal_mode_from_dna_curve(
dna_curve.twist_mode);
for (SplinePtr &spline : curve->splines) {
spline->normal_mode = normal_mode;
}
return curve;
}
/** \} */

View File

@ -1015,7 +1015,6 @@ void BKE_curveprofile_create_samples_even_spacing(CurveProfile *profile,
{
const float total_length = BKE_curveprofile_total_length(profile);
const float segment_length = total_length / n_segments;
float length_travelled = 0.0f;
float distance_to_next_table_point = curveprofile_distance_to_next_table_point(profile, 0);
float distance_to_previous_table_point = 0.0f;
int i_table = 0;
@ -1029,7 +1028,6 @@ void BKE_curveprofile_create_samples_even_spacing(CurveProfile *profile,
for (int i = 1; i < n_segments; i++) {
/* Travel over all of the points that fit inside this segment. */
while (distance_to_next_table_point < segment_left) {
length_travelled += distance_to_next_table_point;
segment_left -= distance_to_next_table_point;
i_table++;
distance_to_next_table_point = curveprofile_distance_to_next_table_point(profile, i_table);
@ -1057,7 +1055,6 @@ void BKE_curveprofile_create_samples_even_spacing(CurveProfile *profile,
/* We sampled in between this table point and the next, so the next travel step is smaller. */
distance_to_next_table_point -= segment_left;
distance_to_previous_table_point += segment_left;
length_travelled += segment_left;
segment_left = segment_length;
}
}

View File

@ -1702,7 +1702,7 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
}
for (int i = 0; i < totloop; i++) {
rgba_uchar_to_float(pPoint[mloop[i].v].color, (const unsigned char *)&col[mloop[i].v].r);
rgba_uchar_to_float(pPoint[mloop[i].v].color, (const unsigned char *)&col[i].r);
}
}
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {

View File

@ -0,0 +1,299 @@
/*
* 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.
*/
#include "BKE_spline.hh"
#include "BKE_attribute_access.hh"
#include "BKE_attribute_math.hh"
#include "BKE_geometry_set.hh"
#include "attribute_access_intern.hh"
/* -------------------------------------------------------------------- */
/** \name Geometry Component Implementation
* \{ */
CurveComponent::CurveComponent() : GeometryComponent(GEO_COMPONENT_TYPE_CURVE)
{
}
CurveComponent::~CurveComponent()
{
this->clear();
}
GeometryComponent *CurveComponent::copy() const
{
CurveComponent *new_component = new CurveComponent();
if (curve_ != nullptr) {
new_component->curve_ = curve_->copy();
new_component->ownership_ = GeometryOwnershipType::Owned;
}
return new_component;
}
void CurveComponent::clear()
{
BLI_assert(this->is_mutable());
if (curve_ != nullptr) {
if (ownership_ == GeometryOwnershipType::Owned) {
delete curve_;
}
curve_ = nullptr;
}
}
bool CurveComponent::has_curve() const
{
return curve_ != nullptr;
}
/* Clear the component and replace it with the new curve. */
void CurveComponent::replace(CurveEval *curve, GeometryOwnershipType ownership)
{
BLI_assert(this->is_mutable());
this->clear();
curve_ = curve;
ownership_ = ownership;
}
CurveEval *CurveComponent::release()
{
BLI_assert(this->is_mutable());
CurveEval *curve = curve_;
curve_ = nullptr;
return curve;
}
const CurveEval *CurveComponent::get_for_read() const
{
return curve_;
}
CurveEval *CurveComponent::get_for_write()
{
BLI_assert(this->is_mutable());
if (ownership_ == GeometryOwnershipType::ReadOnly) {
curve_ = curve_->copy();
ownership_ = GeometryOwnershipType::Owned;
}
return curve_;
}
bool CurveComponent::is_empty() const
{
return curve_ == nullptr;
}
bool CurveComponent::owns_direct_data() const
{
return ownership_ == GeometryOwnershipType::Owned;
}
void CurveComponent::ensure_owns_direct_data()
{
BLI_assert(this->is_mutable());
if (ownership_ != GeometryOwnershipType::Owned) {
curve_ = curve_->copy();
ownership_ = GeometryOwnershipType::Owned;
}
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Attribute Access
* \{ */
int CurveComponent::attribute_domain_size(const AttributeDomain domain) const
{
if (curve_ == nullptr) {
return 0;
}
if (domain == ATTR_DOMAIN_POINT) {
int total = 0;
for (const SplinePtr &spline : curve_->splines) {
total += spline->size();
}
return total;
}
if (domain == ATTR_DOMAIN_CURVE) {
return curve_->splines.size();
}
return 0;
}
namespace blender::bke {
class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider {
using AsReadAttribute = GVArrayPtr (*)(const CurveEval &data);
using AsWriteAttribute = GVMutableArrayPtr (*)(CurveEval &data);
using UpdateOnWrite = void (*)(Spline &spline);
const AsReadAttribute as_read_attribute_;
const AsWriteAttribute as_write_attribute_;
public:
BuiltinSplineAttributeProvider(std::string attribute_name,
const CustomDataType attribute_type,
const WritableEnum writable,
const AsReadAttribute as_read_attribute,
const AsWriteAttribute as_write_attribute)
: BuiltinAttributeProvider(std::move(attribute_name),
ATTR_DOMAIN_CURVE,
attribute_type,
BuiltinAttributeProvider::NonCreatable,
writable,
BuiltinAttributeProvider::NonDeletable),
as_read_attribute_(as_read_attribute),
as_write_attribute_(as_write_attribute)
{
}
GVArrayPtr try_get_for_read(const GeometryComponent &component) const final
{
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
const CurveEval *curve = curve_component.get_for_read();
if (curve == nullptr) {
return {};
}
return as_read_attribute_(*curve);
}
GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const final
{
if (writable_ != Writable) {
return {};
}
CurveComponent &curve_component = static_cast<CurveComponent &>(component);
CurveEval *curve = curve_component.get_for_write();
if (curve == nullptr) {
return {};
}
return as_write_attribute_(*curve);
}
bool try_delete(GeometryComponent &UNUSED(component)) const final
{
return false;
}
bool try_create(GeometryComponent &UNUSED(component),
const AttributeInit &UNUSED(initializer)) const final
{
return false;
}
bool exists(const GeometryComponent &component) const final
{
return component.attribute_domain_size(ATTR_DOMAIN_CURVE) != 0;
}
};
static int get_spline_resolution(const SplinePtr &spline)
{
if (const BezierSpline *bezier_spline = dynamic_cast<const BezierSpline *>(spline.get())) {
return bezier_spline->resolution();
}
if (const NURBSpline *nurb_spline = dynamic_cast<const NURBSpline *>(spline.get())) {
return nurb_spline->resolution();
}
return 1;
}
static void set_spline_resolution(SplinePtr &spline, const int resolution)
{
if (BezierSpline *bezier_spline = dynamic_cast<BezierSpline *>(spline.get())) {
bezier_spline->set_resolution(std::max(resolution, 1));
}
if (NURBSpline *nurb_spline = dynamic_cast<NURBSpline *>(spline.get())) {
nurb_spline->set_resolution(std::max(resolution, 1));
}
}
static GVArrayPtr make_resolution_read_attribute(const CurveEval &curve)
{
return std::make_unique<fn::GVArray_For_DerivedSpan<SplinePtr, int, get_spline_resolution>>(
curve.splines.as_span());
}
static GVMutableArrayPtr make_resolution_write_attribute(CurveEval &curve)
{
return std::make_unique<fn::GVMutableArray_For_DerivedSpan<SplinePtr,
int,
get_spline_resolution,
set_spline_resolution>>(
curve.splines.as_mutable_span());
}
static bool get_cyclic_value(const SplinePtr &spline)
{
return spline->is_cyclic();
}
static void set_cyclic_value(SplinePtr &spline, const bool value)
{
if (spline->is_cyclic() != value) {
spline->set_cyclic(value);
spline->mark_cache_invalid();
}
}
static GVArrayPtr make_cyclic_read_attribute(const CurveEval &curve)
{
return std::make_unique<fn::GVArray_For_DerivedSpan<SplinePtr, bool, get_cyclic_value>>(
curve.splines.as_span());
}
static GVMutableArrayPtr make_cyclic_write_attribute(CurveEval &curve)
{
return std::make_unique<
fn::GVMutableArray_For_DerivedSpan<SplinePtr, bool, get_cyclic_value, set_cyclic_value>>(
curve.splines.as_mutable_span());
}
/**
* In this function all the attribute providers for a curve component are created. Most data
* in this function is statically allocated, because it does not change over time.
*/
static ComponentAttributeProviders create_attribute_providers_for_curve()
{
static BuiltinSplineAttributeProvider resolution("resolution",
CD_PROP_INT32,
BuiltinAttributeProvider::Writable,
make_resolution_read_attribute,
make_resolution_write_attribute);
static BuiltinSplineAttributeProvider cyclic("cyclic",
CD_PROP_BOOL,
BuiltinAttributeProvider::Writable,
make_cyclic_read_attribute,
make_cyclic_write_attribute);
return ComponentAttributeProviders({&resolution, &cyclic}, {});
}
} // namespace blender::bke
const blender::bke::ComponentAttributeProviders *CurveComponent::get_attribute_providers() const
{
static blender::bke::ComponentAttributeProviders providers =
blender::bke::create_attribute_providers_for_curve();
return &providers;
}
/** \} */

View File

@ -42,72 +42,104 @@ InstancesComponent::InstancesComponent() : GeometryComponent(GEO_COMPONENT_TYPE_
GeometryComponent *InstancesComponent::copy() const
{
InstancesComponent *new_component = new InstancesComponent();
new_component->transforms_ = transforms_;
new_component->instanced_data_ = instanced_data_;
new_component->ids_ = ids_;
new_component->instance_reference_handles_ = instance_reference_handles_;
new_component->instance_transforms_ = instance_transforms_;
new_component->instance_ids_ = instance_ids_;
new_component->references_ = references_;
return new_component;
}
void InstancesComponent::reserve(int min_capacity)
{
instance_reference_handles_.reserve(min_capacity);
instance_transforms_.reserve(min_capacity);
instance_ids_.reserve(min_capacity);
}
/**
* Resize the transform, handles, and ID vectors to the specified capacity.
*
* \note This function should be used carefully, only when it's guaranteed
* that the data will be filled.
*/
void InstancesComponent::resize(int capacity)
{
instance_reference_handles_.resize(capacity);
instance_transforms_.resize(capacity);
instance_ids_.resize(capacity);
}
void InstancesComponent::clear()
{
instanced_data_.clear();
transforms_.clear();
ids_.clear();
instance_reference_handles_.clear();
instance_transforms_.clear();
instance_ids_.clear();
references_.clear();
}
void InstancesComponent::add_instance(Object *object, float4x4 transform, const int id)
void InstancesComponent::add_instance(const int instance_handle,
const float4x4 &transform,
const int id)
{
InstancedData data;
data.type = INSTANCE_DATA_TYPE_OBJECT;
data.data.object = object;
this->add_instance(data, transform, id);
BLI_assert(instance_handle >= 0);
BLI_assert(instance_handle < references_.size());
instance_reference_handles_.append(instance_handle);
instance_transforms_.append(transform);
instance_ids_.append(id);
}
void InstancesComponent::add_instance(Collection *collection, float4x4 transform, const int id)
blender::Span<int> InstancesComponent::instance_reference_handles() const
{
InstancedData data;
data.type = INSTANCE_DATA_TYPE_COLLECTION;
data.data.collection = collection;
this->add_instance(data, transform, id);
return instance_reference_handles_;
}
void InstancesComponent::add_instance(InstancedData data, float4x4 transform, const int id)
blender::MutableSpan<int> InstancesComponent::instance_reference_handles()
{
instanced_data_.append(data);
transforms_.append(transform);
ids_.append(id);
return instance_reference_handles_;
}
Span<InstancedData> InstancesComponent::instanced_data() const
blender::MutableSpan<blender::float4x4> InstancesComponent::instance_transforms()
{
return instanced_data_;
return instance_transforms_;
}
blender::Span<blender::float4x4> InstancesComponent::instance_transforms() const
{
return instance_transforms_;
}
Span<float4x4> InstancesComponent::transforms() const
blender::MutableSpan<int> InstancesComponent::instance_ids()
{
return transforms_;
return instance_ids_;
}
blender::Span<int> InstancesComponent::instance_ids() const
{
return instance_ids_;
}
Span<int> InstancesComponent::ids() const
/**
* Returns a handle for the given reference.
* If the reference exists already, the handle of the existing reference is returned.
* Otherwise a new handle is added.
*/
int InstancesComponent::add_reference(InstanceReference reference)
{
return ids_;
return references_.index_of_or_add_as(reference);
}
MutableSpan<float4x4> InstancesComponent::transforms()
blender::Span<InstanceReference> InstancesComponent::references() const
{
return transforms_;
return references_;
}
int InstancesComponent::instances_amount() const
{
const int size = instanced_data_.size();
BLI_assert(transforms_.size() == size);
return size;
return instance_transforms_.size();
}
bool InstancesComponent::is_empty() const
{
return transforms_.size() == 0;
return this->instance_reference_handles_.size() == 0;
}
bool InstancesComponent::owns_direct_data() const
@ -178,8 +210,8 @@ static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids)
blender::Span<int> InstancesComponent::almost_unique_ids() const
{
std::lock_guard lock(almost_unique_ids_mutex_);
if (almost_unique_ids_.size() != ids_.size()) {
almost_unique_ids_ = generate_unique_instance_ids(ids_);
if (almost_unique_ids_.size() != instance_ids_.size()) {
almost_unique_ids_ = generate_unique_instance_ids(instance_ids_);
}
return almost_unique_ids_;
}

View File

@ -24,6 +24,7 @@
#include "BKE_mesh_wrapper.h"
#include "BKE_modifier.h"
#include "BKE_pointcloud.h"
#include "BKE_spline.hh"
#include "BKE_volume.h"
#include "DNA_collection_types.h"
@ -60,6 +61,8 @@ GeometryComponent *GeometryComponent::create(GeometryComponentType component_typ
return new InstancesComponent();
case GEO_COMPONENT_TYPE_VOLUME:
return new VolumeComponent();
case GEO_COMPONENT_TYPE_CURVE:
return new CurveComponent();
}
BLI_assert_unreachable();
return nullptr;
@ -182,6 +185,11 @@ void GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_ma
if (volume != nullptr) {
BKE_volume_min_max(volume, *r_min, *r_max);
}
const CurveEval *curve = this->get_curve_for_read();
if (curve != nullptr) {
/* Using the evaluated positions is somewhat arbitrary, but it is probably expected. */
curve->bounds_min_max(*r_min, *r_max, true);
}
}
std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set)
@ -252,6 +260,13 @@ const Volume *GeometrySet::get_volume_for_read() const
return (component == nullptr) ? nullptr : component->get_for_read();
}
/* Returns a read-only curve or null. */
const CurveEval *GeometrySet::get_curve_for_read() const
{
const CurveComponent *component = this->get_component_for_read<CurveComponent>();
return (component == nullptr) ? nullptr : component->get_for_read();
}
/* Returns true when the geometry set has a point cloud component that has a point cloud. */
bool GeometrySet::has_pointcloud() const
{
@ -273,6 +288,13 @@ bool GeometrySet::has_volume() const
return component != nullptr && component->has_volume();
}
/* Returns true when the geometry set has a curve component that has a curve. */
bool GeometrySet::has_curve() const
{
const CurveComponent *component = this->get_component_for_read<CurveComponent>();
return component != nullptr && component->has_curve();
}
/* Create a new geometry set that only contains the given mesh. */
GeometrySet GeometrySet::create_with_mesh(Mesh *mesh, GeometryOwnershipType ownership)
{
@ -292,6 +314,15 @@ GeometrySet GeometrySet::create_with_pointcloud(PointCloud *pointcloud,
return geometry_set;
}
/* Create a new geometry set that only contains the given curve. */
GeometrySet GeometrySet::create_with_curve(CurveEval *curve, GeometryOwnershipType ownership)
{
GeometrySet geometry_set;
CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
component.replace(curve, ownership);
return geometry_set;
}
/* Clear the existing mesh and replace it with the given one. */
void GeometrySet::replace_mesh(Mesh *mesh, GeometryOwnershipType ownership)
{
@ -299,6 +330,13 @@ void GeometrySet::replace_mesh(Mesh *mesh, GeometryOwnershipType ownership)
component.replace(mesh, ownership);
}
/* Clear the existing curve and replace it with the given one. */
void GeometrySet::replace_curve(CurveEval *curve, GeometryOwnershipType ownership)
{
CurveComponent &component = this->get_component_for_write<CurveComponent>();
component.replace(curve, ownership);
}
/* Clear the existing point cloud and replace with the given one. */
void GeometrySet::replace_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership)
{
@ -334,6 +372,13 @@ Volume *GeometrySet::get_volume_for_write()
return component.get_for_write();
}
/* Returns a mutable curve or null. No ownership is transferred. */
CurveEval *GeometrySet::get_curve_for_write()
{
CurveComponent &component = this->get_component_for_write<CurveComponent>();
return component.get_for_write();
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -19,6 +19,7 @@
#include "BKE_mesh_wrapper.h"
#include "BKE_modifier.h"
#include "BKE_pointcloud.h"
#include "BKE_spline.hh"
#include "DNA_collection_types.h"
#include "DNA_mesh_types.h"
@ -50,6 +51,16 @@ static void add_final_mesh_as_geometry_component(const Object &object, GeometryS
}
}
static void add_curve_data_as_geometry_component(const Object &object, GeometrySet &geometry_set)
{
BLI_assert(object.type == OB_CURVE);
if (object.data != nullptr) {
std::unique_ptr<CurveEval> curve = curve_eval_from_dna_curve(*(Curve *)object.data);
CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
curve_component.replace(curve.release(), GeometryOwnershipType::Owned);
}
}
/**
* \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances.
*/
@ -73,6 +84,9 @@ static GeometrySet object_get_geometry_set_for_read(const Object &object)
if (object.type == OB_MESH) {
add_final_mesh_as_geometry_component(object, geometry_set);
}
else if (object.type == OB_CURVE) {
add_curve_data_as_geometry_component(object, geometry_set);
}
/* TODO: Cover the case of point-clouds without modifiers-- they may not be covered by the
* #geometry_set_eval case above. */
@ -135,21 +149,28 @@ static void geometry_set_collect_recursive(const GeometrySet &geometry_set,
const InstancesComponent &instances_component =
*geometry_set.get_component_for_read<InstancesComponent>();
Span<float4x4> transforms = instances_component.transforms();
Span<InstancedData> instances = instances_component.instanced_data();
for (const int i : instances.index_range()) {
const InstancedData &data = instances[i];
Span<float4x4> transforms = instances_component.instance_transforms();
Span<int> handles = instances_component.instance_reference_handles();
Span<InstanceReference> references = instances_component.references();
for (const int i : transforms.index_range()) {
const InstanceReference &reference = references[handles[i]];
const float4x4 instance_transform = transform * transforms[i];
if (data.type == INSTANCE_DATA_TYPE_OBJECT) {
BLI_assert(data.data.object != nullptr);
const Object &object = *data.data.object;
geometry_set_collect_recursive_object(object, instance_transform, r_sets);
}
else if (data.type == INSTANCE_DATA_TYPE_COLLECTION) {
BLI_assert(data.data.collection != nullptr);
const Collection &collection = *data.data.collection;
geometry_set_collect_recursive_collection_instance(collection, instance_transform, r_sets);
switch (reference.type()) {
case InstanceReference::Type::Object: {
Object &object = reference.object();
geometry_set_collect_recursive_object(object, instance_transform, r_sets);
break;
}
case InstanceReference::Type::Collection: {
Collection &collection = reference.collection();
geometry_set_collect_recursive_collection_instance(
collection, instance_transform, r_sets);
break;
}
case InstanceReference::Type::None: {
break;
}
}
}
}
@ -253,19 +274,24 @@ static bool instances_attribute_foreach_recursive(const GeometrySet &geometry_se
return true;
}
for (const InstancedData &data : instances_component->instanced_data()) {
if (data.type == INSTANCE_DATA_TYPE_OBJECT) {
BLI_assert(data.data.object != nullptr);
const Object &object = *data.data.object;
if (!object_instance_attribute_foreach(object, callback, limit, count)) {
return false;
for (const InstanceReference &reference : instances_component->references()) {
switch (reference.type()) {
case InstanceReference::Type::Object: {
const Object &object = reference.object();
if (!object_instance_attribute_foreach(object, callback, limit, count)) {
return false;
}
break;
}
}
else if (data.type == INSTANCE_DATA_TYPE_COLLECTION) {
BLI_assert(data.data.collection != nullptr);
const Collection &collection = *data.data.collection;
if (!collection_instance_attribute_foreach(collection, callback, limit, count)) {
return false;
case InstanceReference::Type::Collection: {
const Collection &collection = reference.collection();
if (!collection_instance_attribute_foreach(collection, callback, limit, count)) {
return false;
}
break;
}
case InstanceReference::Type::None: {
break;
}
}
}
@ -492,6 +518,28 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups,
}
}
static void join_curve_splines(Span<GeometryInstanceGroup> set_groups, CurveComponent &result)
{
CurveEval *new_curve = new CurveEval();
for (const GeometryInstanceGroup &set_group : set_groups) {
const GeometrySet &set = set_group.geometry_set;
if (!set.has_curve()) {
continue;
}
const CurveEval &source_curve = *set.get_curve_for_read();
for (const SplinePtr &source_spline : source_curve.splines) {
for (const float4x4 &transform : set_group.transforms) {
SplinePtr new_spline = source_spline->copy();
new_spline->transform(transform);
new_curve->splines.append(std::move(new_spline));
}
}
}
result.replace(new_curve);
}
static void join_instance_groups_mesh(Span<GeometryInstanceGroup> set_groups,
bool convert_points_to_vertices,
GeometrySet &result)
@ -558,6 +606,12 @@ static void join_instance_groups_volume(Span<GeometryInstanceGroup> set_groups,
UNUSED_VARS(set_groups, dst_component);
}
static void join_instance_groups_curve(Span<GeometryInstanceGroup> set_groups, GeometrySet &result)
{
CurveComponent &dst_component = result.get_component_for_write<CurveComponent>();
join_curve_splines(set_groups, dst_component);
}
GeometrySet geometry_set_realize_mesh_for_modifier(const GeometrySet &geometry_set)
{
if (!geometry_set.has_instances() && !geometry_set.has_pointcloud()) {
@ -589,6 +643,7 @@ GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set)
join_instance_groups_mesh(set_groups, false, new_geometry_set);
join_instance_groups_pointcloud(set_groups, new_geometry_set);
join_instance_groups_volume(set_groups, new_geometry_set);
join_instance_groups_curve(set_groups, new_geometry_set);
return new_geometry_set;
}

View File

@ -1050,7 +1050,7 @@ void BKE_gpencil_stroke_2d_flat(const bGPDspoint *points,
normalize_v3(locx);
normalize_v3(locy);
/* Calculcate last point first. */
/* Calculate last point first. */
const bGPDspoint *pt_last = &points[totpoints - 1];
float tmp[3];
sub_v3_v3v3(tmp, &pt_last->x, &pt0->x);

View File

@ -757,9 +757,9 @@ void BKE_gpencil_modifiers_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
const bool is_render = (bool)(DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
const bool is_curve_edit = (bool)(GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd) && !is_render);
const bool is_multiedit = (bool)(GPENCIL_MULTIEDIT_SESSIONS_ON(gpd) && !is_render);
const bool do_modifiers = (bool)((!is_multiedit) && (!is_curve_edit) &&
(ob->greasepencil_modifiers.first != NULL) &&
(!GPENCIL_SIMPLIFY_MODIF(scene)));

View File

@ -503,7 +503,7 @@ void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src)
void IDP_SyncGroupTypes(IDProperty *dest, const IDProperty *src, const bool do_arraylen)
{
LISTBASE_FOREACH_MUTABLE (IDProperty *, prop_dst, &src->data.group) {
LISTBASE_FOREACH_MUTABLE (IDProperty *, prop_dst, &dest->data.group) {
const IDProperty *prop_src = IDP_GetPropertyFromGroup((IDProperty *)src, prop_dst->name);
if (prop_src != NULL) {
/* check of we should replace? */

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