Merge branch 'master' into sculpt-dev
This commit is contained in:
commit
fad42fc6c7
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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; \
|
||||
} \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
@ -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
|
@ -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
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -79,6 +79,7 @@ Geometry::Geometry(const NodeType *node_type, const Type type)
|
|||
|
||||
Geometry::~Geometry()
|
||||
{
|
||||
dereference_all_used_nodes();
|
||||
delete bvh;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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",
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'},
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
||||
###################################
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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':
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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);
|
|
@ -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)
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/** \} */
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/** \} */
|
|
@ -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_;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue