Merge branch 'master' into blender2.8

This commit is contained in:
Lukas Tönne 2016-12-01 10:29:46 +01:00
commit ff2a74906a
123 changed files with 1709 additions and 827 deletions

@ -705,6 +705,21 @@ if [ "$WITH_ALL" = true -a "$OPENCOLLADA_SKIP" = false ]; then
fi fi
WARNING "****WARNING****"
PRINT "If you are experiencing issues building Blender, _*TRY A FRESH, CLEAN BUILD FIRST*_!"
PRINT "The same goes for install_deps itself, if you encounter issues, please first erase everything in $SRC and $INST"
PRINT "(provided obviously you did not add anything yourself in those dirs!), and run install_deps.sh again!"
PRINT "Often, changes in the libs built by this script, or in your distro package, cannot be handled simply, so..."
PRINT ""
PRINT "You may also try to use the '--build-foo' options to bypass your distribution's packages"
PRINT "for some troublesome/buggy libraries..."
PRINT ""
PRINT ""
PRINT "Ran with:"
PRINT " install_deps.sh $COMMANDLINE"
PRINT ""
PRINT ""
# This has to be done here, because user might force some versions... # This has to be done here, because user might force some versions...
PYTHON_SOURCE=( "https://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tgz" ) PYTHON_SOURCE=( "https://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tgz" )
@ -777,6 +792,8 @@ However, if you are experiencing linking errors (also when building Blender itse
Please note that until the transition to C++11-built libraries if completed in your distribution, situation will Please note that until the transition to C++11-built libraries if completed in your distribution, situation will
remain fuzzy and incompatibilities may happen..." remain fuzzy and incompatibilities may happen..."
PRINT ""
PRINT ""
CXXFLAGS="$CXXFLAGS -std=c++11" CXXFLAGS="$CXXFLAGS -std=c++11"
export CXXFLAGS export CXXFLAGS
fi fi
@ -4154,16 +4171,6 @@ print_info_ffmpeglink() {
} }
print_info() { print_info() {
PRINT ""
PRINT ""
WARNING "****WARNING****"
PRINT "If you are experiencing issues building Blender, _*TRY A FRESH, CLEAN BUILD FIRST*_!"
PRINT "The same goes for install_deps itself, if you encounter issues, please first erase everything in $SRC and $INST"
PRINT "(provided obviously you did not add anything yourself in those dirs!), and run install_deps.sh again!"
PRINT "Often, changes in the libs built by this script, or in your distro package, cannot be handled simply, so..."
PRINT ""
PRINT "You may also try to use the '--build-foo' options to bypass your distribution's packages"
PRINT "for some troublesome/buggy libraries..."
PRINT "" PRINT ""
PRINT "" PRINT ""
PRINT "Ran with:" PRINT "Ran with:"

@ -112,7 +112,7 @@ set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221")
# MSVC only, Mingw doesnt need # MSVC only, Mingw doesnt need
if(CMAKE_CL_64) if(CMAKE_CL_64)
set(PLATFORM_LINKFLAGS "/MACHINE:X64 /OPT:NOREF ${PLATFORM_LINKFLAGS}") set(PLATFORM_LINKFLAGS "/MACHINE:X64 ${PLATFORM_LINKFLAGS}")
else() else()
set(PLATFORM_LINKFLAGS "/MACHINE:IX86 /LARGEADDRESSAWARE ${PLATFORM_LINKFLAGS}") set(PLATFORM_LINKFLAGS "/MACHINE:IX86 /LARGEADDRESSAWARE ${PLATFORM_LINKFLAGS}")
endif() endif()

@ -77,7 +77,7 @@ namespace std {
void resize(size_type new_size) void resize(size_type new_size)
{ resize(new_size, T()); } { resize(new_size, T()); }
#if defined(_VECTOR_) #if defined(_VECTOR_) && (_MSC_VER<1910)
// workaround MSVC std::vector implementation // workaround MSVC std::vector implementation
void resize(size_type new_size, const value_type& x) void resize(size_type new_size, const value_type& x)
{ {
@ -110,7 +110,7 @@ namespace std {
vector_base::insert(vector_base::end(), new_size - vector_base::size(), x); vector_base::insert(vector_base::end(), new_size - vector_base::size(), x);
} }
#else #else
// either GCC 4.1 or non-GCC // either GCC 4.1, MSVC2017 or non-GCC
// default implementation which should always work. // default implementation which should always work.
void resize(size_type new_size, const value_type& x) void resize(size_type new_size, const value_type& x)
{ {

@ -369,7 +369,8 @@ typedef unsigned int cl_GLenum;
#endif #endif
/* Define basic vector types */ /* Define basic vector types */
#if defined( __VEC__ ) /* WOrkaround for ppc64el platform: conflicts with bool from C++. */
#if defined( __VEC__ ) && !(defined(__PPC64__) && defined(__LITTLE_ENDIAN__))
#include <altivec.h> /* may be omitted depending on compiler. AltiVec spec provides no way to detect whether the header is required. */ #include <altivec.h> /* may be omitted depending on compiler. AltiVec spec provides no way to detect whether the header is required. */
typedef vector unsigned char __cl_uchar16; typedef vector unsigned char __cl_uchar16;
typedef vector signed char __cl_char16; typedef vector signed char __cl_char16;

@ -59,7 +59,8 @@
# include <unistd.h> # include <unistd.h>
#endif #endif
#if defined(HAVE_SYSCALL_H) || defined(HAVE_SYS_SYSCALL_H) // Hurd does not have SYS_write.
#if (defined(HAVE_SYSCALL_H) || defined(HAVE_SYS_SYSCALL_H)) && !defined(__GNU__)
# define safe_write(fd, s, len) syscall(SYS_write, fd, s, len) # define safe_write(fd, s, len) syscall(SYS_write, fd, s, len)
#else #else
// Not so safe, but what can you do? // Not so safe, but what can you do?

@ -111,7 +111,7 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
result[n++] = *(sp+2); result[n++] = *(sp+2);
#elif defined(_CALL_SYSV) #elif defined(_CALL_SYSV)
result[n++] = *(sp+1); result[n++] = *(sp+1);
#elif defined(__APPLE__) || (defined(__linux) && defined(__PPC64__)) #elif defined(__APPLE__) || ((defined(__linux) || defined(__linux__)) && defined(__PPC64__))
// This check is in case the compiler doesn't define _CALL_AIX/etc. // This check is in case the compiler doesn't define _CALL_AIX/etc.
result[n++] = *(sp+2); result[n++] = *(sp+2);
#elif defined(__linux) #elif defined(__linux)

@ -808,7 +808,7 @@ bool range_tree_uint_retake(RangeTreeUInt *rt, const uint value)
uint range_tree_uint_take_any(RangeTreeUInt *rt) uint range_tree_uint_take_any(RangeTreeUInt *rt)
{ {
Node *node = node = rt->list.first; Node *node = rt->list.first;
uint value = node->min; uint value = node->min;
if (value == node->max) { if (value == node->max) {
rt_node_remove(rt, node); rt_node_remove(rt, node);

@ -110,10 +110,10 @@ void AUD_LimiterReader::read(int& length, bool& eos, sample_t* buffer)
eos = true; eos = true;
} }
if(position < m_start * rate) if(position < int(m_start * rate))
{ {
int len2 = length; int len2 = length;
for(int len = m_start * rate - position; for(int len = int(m_start * rate) - position;
len2 == length && !eos; len2 == length && !eos;
len -= length) len -= length)
{ {

@ -30,7 +30,7 @@ import _cycles
enum_devices = ( enum_devices = (
('CPU', "CPU", "Use CPU for rendering"), ('CPU', "CPU", "Use CPU for rendering"),
('GPU', "GPU Compute", "Use GPU compute device for rendering, configured in user preferences"), ('GPU', "GPU Compute", "Use GPU compute device for rendering, configured in the system tab in the user preferences"),
) )
if _cycles.with_network: if _cycles.with_network:
@ -129,6 +129,16 @@ enum_device_type = (
('OPENCL', "OpenCL", "OpenCL", 2) ('OPENCL', "OpenCL", "OpenCL", 2)
) )
enum_texture_limit = (
('OFF', "No Limit", "No texture size limit", 0),
('128', "128", "Limit texture size to 128 pixels", 1),
('256', "256", "Limit texture size to 256 pixels", 2),
('512', "512", "Limit texture size to 512 pixels", 3),
('1024', "1024", "Limit texture size to 1024 pixels", 4),
('2048', "2048", "Limit texture size to 2048 pixels", 5),
('4096', "4096", "Limit texture size to 4096 pixels", 6),
('8192', "8192", "Limit texture size to 8192 pixels", 7),
)
class CyclesRenderSettings(bpy.types.PropertyGroup): class CyclesRenderSettings(bpy.types.PropertyGroup):
@classmethod @classmethod
@ -566,6 +576,19 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
min=0.0, max=5.0 min=0.0, max=5.0
) )
cls.use_distance_cull = BoolProperty(
name="Use Distance Cull",
description="Allow objects to be culled based on the distance from camera",
default=False,
)
cls.distance_cull_margin = FloatProperty(
name="Cull Distance",
description="Cull objects which are further away from camera than this distance",
default=50,
min=0.0
)
cls.motion_blur_position = EnumProperty( cls.motion_blur_position = EnumProperty(
name="Motion Blur Position", name="Motion Blur Position",
default='CENTER', default='CENTER',
@ -595,6 +618,20 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
min=0.0, max=1.0, min=0.0, max=1.0,
) )
cls.texture_limit = EnumProperty(
name="Viewport Texture Limit",
default='OFF',
description="Limit texture size used by viewport rendering",
items=enum_texture_limit
)
cls.texture_limit_render = EnumProperty(
name="Render Texture Limit",
default='OFF',
description="Limit texture size used by final rendering",
items=enum_texture_limit
)
# Various fine-tuning debug flags # Various fine-tuning debug flags
def devices_update_callback(self, context): def devices_update_callback(self, context):
@ -1016,6 +1053,12 @@ class CyclesObjectSettings(bpy.types.PropertyGroup):
default=False, default=False,
) )
cls.use_distance_cull = BoolProperty(
name="Use Distance Cull",
description="Allow this object and its duplicators to be culled by distance from camera",
default=False,
)
cls.use_adaptive_subdivision = BoolProperty( cls.use_adaptive_subdivision = BoolProperty(
name="Use Adaptive Subdivision", name="Use Adaptive Subdivision",
description="Use adaptive render time subdivision", description="Use adaptive render time subdivision",
@ -1126,7 +1169,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
def get_devices(self): def get_devices(self):
import _cycles import _cycles
# Layout of the device tuples: (Name, Type, Internal ID, Persistent ID) # Layout of the device tuples: (Name, Type, Persistent ID)
device_list = _cycles.available_devices() device_list = _cycles.available_devices()
cuda_devices = [] cuda_devices = []
@ -1174,21 +1217,19 @@ class CyclesPreferences(bpy.types.AddonPreferences):
def draw_impl(self, layout, context): def draw_impl(self, layout, context):
layout.label(text="Compute Device:") layout.label(text="Cycles Compute Device:")
layout.row().prop(self, "compute_device_type", expand=True) layout.row().prop(self, "compute_device_type", expand=True)
cuda_devices, opencl_devices = self.get_devices() cuda_devices, opencl_devices = self.get_devices()
row = layout.row() row = layout.row()
if cuda_devices: if self.compute_device_type == 'CUDA' and cuda_devices:
col = row.column(align=True) col = row.column(align=True)
col.label(text="CUDA devices:")
for device in cuda_devices: for device in cuda_devices:
col.prop(device, "use", text=device.name, toggle=True) col.prop(device, "use", text=device.name, toggle=True)
if opencl_devices: if self.compute_device_type == 'OPENCL' and opencl_devices:
col = row.column(align=True) col = row.column(align=True)
col.label(text="OpenCL devices:")
for device in opencl_devices: for device in opencl_devices:
col.prop(device, "use", text=device.name, toggle=True) col.prop(device, "use", text=device.name, toggle=True)

@ -769,6 +769,8 @@ class CyclesObject_PT_cycles_settings(CyclesButtonsPanel, Panel):
row = col.row() row = col.row()
row.active = scene.render.use_simplify and cscene.use_camera_cull row.active = scene.render.use_simplify and cscene.use_camera_cull
row.prop(cob, "use_camera_cull") row.prop(cob, "use_camera_cull")
row.active = scene.render.use_simplify and cscene.use_distance_cull
row.prop(cob, "use_distance_cull")
class CYCLES_OT_use_shading_nodes(Operator): class CYCLES_OT_use_shading_nodes(Operator):
@ -1523,22 +1525,35 @@ class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel):
cscene = scene.cycles cscene = scene.cycles
layout.active = rd.use_simplify layout.active = rd.use_simplify
col = layout.column(align=True)
col.label(text="Subdivision")
row = col.row(align=True)
row.prop(rd, "simplify_subdivision", text="Viewport")
row.prop(rd, "simplify_subdivision_render", text="Render")
col = layout.column(align=True)
split = col.split()
sub = split.column()
sub.label(text="Texture Limit Viewport")
sub.prop(cscene, "texture_limit", text="")
sub = split.column()
sub.label(text="Texture Limit Render")
sub.prop(cscene, "texture_limit_render", text="")
split = layout.split() split = layout.split()
col = split.column() col = split.column()
col.label(text="Viewport:")
col.prop(rd, "simplify_subdivision", text="Subdivision")
col = split.column()
col.label(text="Render:")
col.prop(rd, "simplify_subdivision_render", text="Subdivision")
col = layout.column()
col.prop(cscene, "use_camera_cull") col.prop(cscene, "use_camera_cull")
subsub = col.column() row = col.row()
subsub.active = cscene.use_camera_cull row.active = cscene.use_camera_cull
subsub.prop(cscene, "camera_cull_margin") row.prop(cscene, "camera_cull_margin")
col = split.column()
col.prop(cscene, "use_distance_cull")
row = col.row()
row.active = cscene.use_distance_cull
row.prop(cscene, "distance_cull_margin", text="Distance")
def draw_device(self, context): def draw_device(self, context):
scene = context.scene scene = context.scene
@ -1552,11 +1567,9 @@ def draw_device(self, context):
split = layout.split(percentage=1/3) split = layout.split(percentage=1/3)
split.label("Device:") split.label("Device:")
row = split.row(align=True) row = split.row()
sub = row.split(align=True) row.active = show_device_selection(context)
sub.active = show_device_selection(context) row.prop(cscene, "device", text="")
sub.prop(cscene, "device", text="")
row.operator("wm.addon_userpref_show", text="", icon='PREFERENCES').module = __package__
if engine.with_osl() and use_cpu(context): if engine.with_osl() and use_cpu(context):
layout.prop(cscene, "shading_system") layout.prop(cscene, "shading_system")

@ -172,6 +172,24 @@ def custom_bake_remap(scene):
@persistent @persistent
def do_versions(self): def do_versions(self):
if bpy.context.user_preferences.version <= (2, 78, 1):
prop = bpy.context.user_preferences.addons[__package__].preferences
system = bpy.context.user_preferences.system
if not prop.is_property_set("compute_device_type"):
# Device might not currently be available so this can fail
try:
if system.legacy_compute_device_type == 1:
prop.compute_device_type = 'OPENCL'
elif system.legacy_compute_device_type == 2:
prop.compute_device_type = 'CUDA'
else:
prop.compute_device_type = 'NONE'
except:
pass
# Init device list for UI
prop.get_devices()
# We don't modify startup file because it assumes to # We don't modify startup file because it assumes to
# have all the default values only. # have all the default values only.
if not bpy.data.is_saved: if not bpy.data.is_saved:

@ -88,6 +88,143 @@ static uint object_ray_visibility(BL::Object& b_ob)
return flag; return flag;
} }
/* Culling */
class BlenderObjectCulling
{
public:
BlenderObjectCulling(Scene *scene, BL::Scene& b_scene)
: use_scene_camera_cull(false),
use_camera_cull(false),
camera_cull_margin(0.0f),
use_scene_distance_cull(false),
use_distance_cull(false),
distance_cull_margin(0.0f)
{
if(b_scene.render().use_simplify()) {
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
use_scene_camera_cull = scene->camera->type != CAMERA_PANORAMA &&
!b_scene.render().use_multiview() &&
get_boolean(cscene, "use_camera_cull");
use_scene_distance_cull = scene->camera->type != CAMERA_PANORAMA &&
!b_scene.render().use_multiview() &&
get_boolean(cscene, "use_distance_cull");
camera_cull_margin = get_float(cscene, "camera_cull_margin");
distance_cull_margin = get_float(cscene, "distance_cull_margin");
if (distance_cull_margin == 0.0f) {
use_scene_distance_cull = false;
}
}
}
void init_object(Scene *scene, BL::Object& b_ob)
{
if(!use_scene_camera_cull && !use_scene_distance_cull) {
return;
}
PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
use_camera_cull = use_scene_camera_cull && get_boolean(cobject, "use_camera_cull");
use_distance_cull = use_scene_distance_cull && get_boolean(cobject, "use_distance_cull");
if(use_camera_cull || use_distance_cull) {
/* Need to have proper projection matrix. */
scene->camera->update();
}
}
bool test(Scene *scene, BL::Object& b_ob, Transform& tfm)
{
if(!use_camera_cull && !use_distance_cull) {
return false;
}
/* Compute world space bounding box corners. */
float3 bb[8];
BL::Array<float, 24> boundbox = b_ob.bound_box();
for(int i = 0; i < 8; ++i) {
float3 p = make_float3(boundbox[3 * i + 0],
boundbox[3 * i + 1],
boundbox[3 * i + 2]);
bb[i] = transform_point(&tfm, p);
}
bool camera_culled = use_camera_cull && test_camera(scene, bb);
bool distance_culled = use_distance_cull && test_distance(scene, bb);
return ((camera_culled && distance_culled) ||
(camera_culled && !use_distance_cull) ||
(distance_culled && !use_camera_cull));
}
private:
/* TODO(sergey): Not really optimal, consider approaches based on k-DOP in order
* to reduce number of objects which are wrongly considered visible.
*/
bool test_camera(Scene *scene, float3 bb[8])
{
Camera *cam = scene->camera;
Transform& worldtondc = cam->worldtondc;
float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
bool all_behind = true;
for(int i = 0; i < 8; ++i) {
float3 p = bb[i];
float4 b = make_float4(p.x, p.y, p.z, 1.0f);
float4 c = make_float4(dot(worldtondc.x, b),
dot(worldtondc.y, b),
dot(worldtondc.z, b),
dot(worldtondc.w, b));
p = float4_to_float3(c / c.w);
if(c.z < 0.0f) {
p.x = 1.0f - p.x;
p.y = 1.0f - p.y;
}
if(c.z >= -camera_cull_margin) {
all_behind = false;
}
bb_min = min(bb_min, p);
bb_max = max(bb_max, p);
}
if(all_behind) {
return true;
}
return (bb_min.x >= 1.0f + camera_cull_margin ||
bb_min.y >= 1.0f + camera_cull_margin ||
bb_max.x <= -camera_cull_margin ||
bb_max.y <= -camera_cull_margin);
}
bool test_distance(Scene *scene, float3 bb[8])
{
float3 camera_position = transform_get_column(&scene->camera->matrix, 3);
float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
/* Find min & max points for x & y & z on bounding box */
for(int i = 0; i < 8; ++i) {
float3 p = bb[i];
bb_min = min(bb_min, p);
bb_max = max(bb_max, p);
}
float3 closest_point = max(min(bb_max,camera_position),bb_min);
return (len_squared(camera_position - closest_point) >
distance_cull_margin * distance_cull_margin);
}
bool use_scene_camera_cull;
bool use_camera_cull;
float camera_cull_margin;
bool use_scene_distance_cull;
bool use_distance_cull;
float distance_cull_margin;
};
/* Light */ /* Light */
void BlenderSync::sync_light(BL::Object& b_parent, void BlenderSync::sync_light(BL::Object& b_parent,
@ -235,55 +372,6 @@ void BlenderSync::sync_background_light(bool use_portal)
/* Object */ /* Object */
/* TODO(sergey): Not really optimal, consider approaches based on k-DOP in order
* to reduce number of objects which are wrongly considered visible.
*/
static bool object_boundbox_clip(Scene *scene,
BL::Object& b_ob,
Transform& tfm,
float margin)
{
Camera *cam = scene->camera;
Transform& worldtondc = cam->worldtondc;
BL::Array<float, 24> boundbox = b_ob.bound_box();
float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
bool all_behind = true;
for(int i = 0; i < 8; ++i) {
float3 p = make_float3(boundbox[3 * i + 0],
boundbox[3 * i + 1],
boundbox[3 * i + 2]);
p = transform_point(&tfm, p);
float4 b = make_float4(p.x, p.y, p.z, 1.0f);
float4 c = make_float4(dot(worldtondc.x, b),
dot(worldtondc.y, b),
dot(worldtondc.z, b),
dot(worldtondc.w, b));
p = float4_to_float3(c / c.w);
if(c.z < 0.0f) {
p.x = 1.0f - p.x;
p.y = 1.0f - p.y;
}
if(c.z >= -margin) {
all_behind = false;
}
bb_min = min(bb_min, p);
bb_max = max(bb_max, p);
}
if(!all_behind) {
if(bb_min.x >= 1.0f + margin ||
bb_min.y >= 1.0f + margin ||
bb_max.x <= -margin ||
bb_max.y <= -margin)
{
return true;
}
return false;
}
return true;
}
Object *BlenderSync::sync_object(BL::Object& b_parent, Object *BlenderSync::sync_object(BL::Object& b_parent,
int persistent_id[OBJECT_PERSISTENT_ID_SIZE], int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
BL::DupliObject& b_dupli_ob, BL::DupliObject& b_dupli_ob,
@ -291,8 +379,7 @@ Object *BlenderSync::sync_object(BL::Object& b_parent,
uint layer_flag, uint layer_flag,
float motion_time, float motion_time,
bool hide_tris, bool hide_tris,
bool use_camera_cull, BlenderObjectCulling& culling,
float camera_cull_margin,
bool *use_portal) bool *use_portal)
{ {
BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent); BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent);
@ -308,11 +395,12 @@ Object *BlenderSync::sync_object(BL::Object& b_parent,
} }
/* only interested in object that we can create meshes from */ /* only interested in object that we can create meshes from */
if(!object_is_mesh(b_ob)) if(!object_is_mesh(b_ob)) {
return NULL; return NULL;
}
/* Perform camera space culling. */ /* Perform object culling. */
if(use_camera_cull && object_boundbox_clip(scene, b_ob, tfm, camera_cull_margin)) { if(culling.test(scene, b_ob, tfm)) {
return NULL; return NULL;
} }
@ -519,17 +607,8 @@ void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time)
mesh_motion_synced.clear(); mesh_motion_synced.clear();
} }
bool allow_camera_cull = false; /* initialize culling */
float camera_cull_margin = 0.0f; BlenderObjectCulling culling(scene, b_scene);
if(b_scene.render().use_simplify()) {
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
allow_camera_cull = scene->camera->type != CAMERA_PANORAMA &&
!b_scene.render().use_multiview() &&
get_boolean(cscene, "use_camera_cull");
if(allow_camera_cull) {
camera_cull_margin = get_float(cscene, "camera_cull_margin");
}
}
/* object loop */ /* object loop */
BL::Scene::object_bases_iterator b_base; BL::Scene::object_bases_iterator b_base;
@ -561,12 +640,9 @@ void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time)
if(!hide) { if(!hide) {
progress.set_sync_status("Synchronizing object", b_ob.name()); progress.set_sync_status("Synchronizing object", b_ob.name());
PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles"); /* load per-object culling data */
bool use_camera_cull = allow_camera_cull && get_boolean(cobject, "use_camera_cull"); culling.init_object(scene, b_ob);
if(use_camera_cull) {
/* Need to have proper projection matrix. */
scene->camera->update();
}
if(b_ob.is_duplicator() && !object_render_hide_duplis(b_ob)) { if(b_ob.is_duplicator() && !object_render_hide_duplis(b_ob)) {
/* dupli objects */ /* dupli objects */
b_ob.dupli_list_create(b_scene, dupli_settings); b_ob.dupli_list_create(b_scene, dupli_settings);
@ -593,8 +669,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time)
ob_layer, ob_layer,
motion_time, motion_time,
hide_tris, hide_tris,
use_camera_cull, culling,
camera_cull_margin,
&use_portal); &use_portal);
} }
} }
@ -616,8 +691,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time)
ob_layer, ob_layer,
motion_time, motion_time,
hide_tris, hide_tris,
use_camera_cull, culling,
camera_cull_margin,
&use_portal); &use_portal);
} }
} }

@ -126,8 +126,8 @@ void BlenderSession::create_session()
/* setup callbacks for builtin image support */ /* setup callbacks for builtin image support */
scene->image_manager->builtin_image_info_cb = function_bind(&BlenderSession::builtin_image_info, this, _1, _2, _3, _4, _5, _6, _7); scene->image_manager->builtin_image_info_cb = function_bind(&BlenderSession::builtin_image_info, this, _1, _2, _3, _4, _5, _6, _7);
scene->image_manager->builtin_image_pixels_cb = function_bind(&BlenderSession::builtin_image_pixels, this, _1, _2, _3); scene->image_manager->builtin_image_pixels_cb = function_bind(&BlenderSession::builtin_image_pixels, this, _1, _2, _3, _4);
scene->image_manager->builtin_image_float_pixels_cb = function_bind(&BlenderSession::builtin_image_float_pixels, this, _1, _2, _3); scene->image_manager->builtin_image_float_pixels_cb = function_bind(&BlenderSession::builtin_image_float_pixels, this, _1, _2, _3, _4);
/* create session */ /* create session */
session = new Session(session_params); session = new Session(session_params);
@ -1080,7 +1080,13 @@ int BlenderSession::builtin_image_frame(const string &builtin_name)
return atoi(builtin_name.substr(last + 1, builtin_name.size() - last - 1).c_str()); return atoi(builtin_name.substr(last + 1, builtin_name.size() - last - 1).c_str());
} }
void BlenderSession::builtin_image_info(const string &builtin_name, void *builtin_data, bool &is_float, int &width, int &height, int &depth, int &channels) void BlenderSession::builtin_image_info(const string &builtin_name,
void *builtin_data,
bool &is_float,
int &width,
int &height,
int &depth,
int &channels)
{ {
/* empty image */ /* empty image */
is_float = false; is_float = false;
@ -1158,60 +1164,67 @@ void BlenderSession::builtin_image_info(const string &builtin_name, void *builti
} }
} }
bool BlenderSession::builtin_image_pixels(const string &builtin_name, void *builtin_data, unsigned char *pixels) bool BlenderSession::builtin_image_pixels(const string &builtin_name,
void *builtin_data,
unsigned char *pixels,
const size_t pixels_size)
{ {
if(!builtin_data) if(!builtin_data) {
return false; return false;
}
int frame = builtin_image_frame(builtin_name); const int frame = builtin_image_frame(builtin_name);
PointerRNA ptr; PointerRNA ptr;
RNA_id_pointer_create((ID*)builtin_data, &ptr); RNA_id_pointer_create((ID*)builtin_data, &ptr);
BL::Image b_image(ptr); BL::Image b_image(ptr);
int width = b_image.size()[0]; const int width = b_image.size()[0];
int height = b_image.size()[1]; const int height = b_image.size()[1];
int channels = b_image.channels(); const int channels = b_image.channels();
unsigned char *image_pixels; unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame);
image_pixels = image_get_pixels_for_frame(b_image, frame); const size_t num_pixels = ((size_t)width) * height;
size_t num_pixels = ((size_t)width) * height;
if(image_pixels) { if(image_pixels && num_pixels * channels == pixels_size) {
memcpy(pixels, image_pixels, num_pixels * channels * sizeof(unsigned char)); memcpy(pixels, image_pixels, pixels_size * sizeof(unsigned char));
MEM_freeN(image_pixels); MEM_freeN(image_pixels);
} }
else { else {
if(channels == 1) { if(channels == 1) {
memset(pixels, 0, num_pixels * sizeof(unsigned char)); memset(pixels, 0, pixels_size * sizeof(unsigned char));
} }
else { else {
const size_t num_pixels_safe = pixels_size / channels;
unsigned char *cp = pixels; unsigned char *cp = pixels;
for(size_t i = 0; i < num_pixels; i++, cp += channels) { for(size_t i = 0; i < num_pixels_safe; i++, cp += channels) {
cp[0] = 255; cp[0] = 255;
cp[1] = 0; cp[1] = 0;
cp[2] = 255; cp[2] = 255;
if(channels == 4) if(channels == 4) {
cp[3] = 255; cp[3] = 255;
}
} }
} }
} }
/* Premultiply, byte images are always straight for Blender. */
/* premultiply, byte images are always straight for blender */
unsigned char *cp = pixels; unsigned char *cp = pixels;
for(size_t i = 0; i < num_pixels; i++, cp += channels) { for(size_t i = 0; i < num_pixels; i++, cp += channels) {
cp[0] = (cp[0] * cp[3]) >> 8; cp[0] = (cp[0] * cp[3]) >> 8;
cp[1] = (cp[1] * cp[3]) >> 8; cp[1] = (cp[1] * cp[3]) >> 8;
cp[2] = (cp[2] * cp[3]) >> 8; cp[2] = (cp[2] * cp[3]) >> 8;
} }
return true; return true;
} }
bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void *builtin_data, float *pixels) bool BlenderSession::builtin_image_float_pixels(const string &builtin_name,
void *builtin_data,
float *pixels,
const size_t pixels_size)
{ {
if(!builtin_data) if(!builtin_data) {
return false; return false;
}
PointerRNA ptr; PointerRNA ptr;
RNA_id_pointer_create((ID*)builtin_data, &ptr); RNA_id_pointer_create((ID*)builtin_data, &ptr);
@ -1222,16 +1235,16 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void
BL::Image b_image(b_id); BL::Image b_image(b_id);
int frame = builtin_image_frame(builtin_name); int frame = builtin_image_frame(builtin_name);
int width = b_image.size()[0]; const int width = b_image.size()[0];
int height = b_image.size()[1]; const int height = b_image.size()[1];
int channels = b_image.channels(); const int channels = b_image.channels();
float *image_pixels; float *image_pixels;
image_pixels = image_get_float_pixels_for_frame(b_image, frame); image_pixels = image_get_float_pixels_for_frame(b_image, frame);
size_t num_pixels = ((size_t)width) * height; const size_t num_pixels = ((size_t)width) * height;
if(image_pixels) { if(image_pixels && num_pixels * channels == pixels_size) {
memcpy(pixels, image_pixels, num_pixels * channels * sizeof(float)); memcpy(pixels, image_pixels, pixels_size * sizeof(float));
MEM_freeN(image_pixels); MEM_freeN(image_pixels);
} }
else { else {
@ -1239,13 +1252,15 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void
memset(pixels, 0, num_pixels * sizeof(float)); memset(pixels, 0, num_pixels * sizeof(float));
} }
else { else {
const size_t num_pixels_safe = pixels_size / channels;
float *fp = pixels; float *fp = pixels;
for(int i = 0; i < num_pixels; i++, fp += channels) { for(int i = 0; i < num_pixels_safe; i++, fp += channels) {
fp[0] = 1.0f; fp[0] = 1.0f;
fp[1] = 0.0f; fp[1] = 0.0f;
fp[2] = 1.0f; fp[2] = 1.0f;
if(channels == 4) if(channels == 4) {
fp[3] = 1.0f; fp[3] = 1.0f;
}
} }
} }
} }
@ -1257,8 +1272,9 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void
BL::Object b_ob(b_id); BL::Object b_ob(b_id);
BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob); BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob);
if(!b_domain) if(!b_domain) {
return false; return false;
}
int3 resolution = get_int3(b_domain.domain_resolution()); int3 resolution = get_int3(b_domain.domain_resolution());
int length, amplify = (b_domain.use_high_resolution())? b_domain.amplify() + 1: 1; int length, amplify = (b_domain.use_high_resolution())? b_domain.amplify() + 1: 1;
@ -1270,10 +1286,10 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void
amplify = 1; amplify = 1;
} }
int width = resolution.x * amplify; const int width = resolution.x * amplify;
int height = resolution.y * amplify; const int height = resolution.y * amplify;
int depth = resolution.z * amplify; const int depth = resolution.z * amplify;
size_t num_pixels = ((size_t)width) * height * depth; const size_t num_pixels = ((size_t)width) * height * depth;
if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY)) { if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY)) {
SmokeDomainSettings_density_grid_get_length(&b_domain.ptr, &length); SmokeDomainSettings_density_grid_get_length(&b_domain.ptr, &length);

@ -145,9 +145,21 @@ protected:
void do_write_update_render_tile(RenderTile& rtile, bool do_update_only); void do_write_update_render_tile(RenderTile& rtile, bool do_update_only);
int builtin_image_frame(const string &builtin_name); int builtin_image_frame(const string &builtin_name);
void builtin_image_info(const string &builtin_name, void *builtin_data, bool &is_float, int &width, int &height, int &depth, int &channels); void builtin_image_info(const string &builtin_name,
bool builtin_image_pixels(const string &builtin_name, void *builtin_data, unsigned char *pixels); void *builtin_data,
bool builtin_image_float_pixels(const string &builtin_name, void *builtin_data, float *pixels); bool &is_float,
int &width,
int &height,
int &depth,
int &channels);
bool builtin_image_pixels(const string &builtin_name,
void *builtin_data,
unsigned char *pixels,
const size_t pixels_size);
bool builtin_image_float_pixels(const string &builtin_name,
void *builtin_data,
float *pixels,
const size_t pixels_size);
/* Update tile manager to reflect resumable render settings. */ /* Update tile manager to reflect resumable render settings. */
void update_resumable_tile_manager(int num_samples); void update_resumable_tile_manager(int num_samples);

@ -496,6 +496,20 @@ SceneParams BlenderSync::get_scene_params(BL::Scene& b_scene,
else else
params.persistent_data = false; params.persistent_data = false;
int texture_limit;
if(background) {
texture_limit = RNA_enum_get(&cscene, "texture_limit_render");
}
else {
texture_limit = RNA_enum_get(&cscene, "texture_limit");
}
if(texture_limit > 0 && b_scene.render().use_simplify()) {
params.texture_limit = 1 << (texture_limit + 6);
}
else {
params.texture_limit = 0;
}
#if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86))) #if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86)))
if(is_cpu) { if(is_cpu) {
params.use_qbvh = DebugFlags().cpu.qbvh && system_cpu_support_sse2(); params.use_qbvh = DebugFlags().cpu.qbvh && system_cpu_support_sse2();

@ -35,6 +35,7 @@
CCL_NAMESPACE_BEGIN CCL_NAMESPACE_BEGIN
class Background; class Background;
class BlenderObjectCulling;
class Camera; class Camera;
class Film; class Film;
class Light; class Light;
@ -122,8 +123,7 @@ private:
uint layer_flag, uint layer_flag,
float motion_time, float motion_time,
bool hide_tris, bool hide_tris,
bool use_camera_cull, BlenderObjectCulling& culling,
float camera_cull_margin,
bool *use_portal); bool *use_portal);
void sync_light(BL::Object& b_parent, void sync_light(BL::Object& b_parent,
int persistent_id[OBJECT_PERSISTENT_ID_SIZE], int persistent_id[OBJECT_PERSISTENT_ID_SIZE],

@ -1418,7 +1418,11 @@ void device_cuda_info(vector<DeviceInfo>& devices)
cuDeviceGetAttribute(&pci_location[0], CU_DEVICE_ATTRIBUTE_PCI_DOMAIN_ID, num); cuDeviceGetAttribute(&pci_location[0], CU_DEVICE_ATTRIBUTE_PCI_DOMAIN_ID, num);
cuDeviceGetAttribute(&pci_location[1], CU_DEVICE_ATTRIBUTE_PCI_BUS_ID, num); cuDeviceGetAttribute(&pci_location[1], CU_DEVICE_ATTRIBUTE_PCI_BUS_ID, num);
cuDeviceGetAttribute(&pci_location[2], CU_DEVICE_ATTRIBUTE_PCI_DEVICE_ID, num); cuDeviceGetAttribute(&pci_location[2], CU_DEVICE_ATTRIBUTE_PCI_DEVICE_ID, num);
info.id = string_printf("CUDA_%s_%04x:%02x:%02x", name, pci_location[0], pci_location[1], pci_location[2]); info.id = string_printf("CUDA_%s_%04x:%02x:%02x",
name,
(unsigned int)pci_location[0],
(unsigned int)pci_location[1],
(unsigned int)pci_location[2]);
/* if device has a kernel timeout, assume it is used for display */ /* if device has a kernel timeout, assume it is used for display */
if(cuDeviceGetAttribute(&attr, CU_DEVICE_ATTRIBUTE_KERNEL_EXEC_TIMEOUT, num) == CUDA_SUCCESS && attr == 1) { if(cuDeviceGetAttribute(&attr, CU_DEVICE_ATTRIBUTE_KERNEL_EXEC_TIMEOUT, num) == CUDA_SUCCESS && attr == 1) {

@ -16,14 +16,14 @@
#ifdef WITH_OPENCL #ifdef WITH_OPENCL
#include "clew.h"
#include "device.h" #include "device.h"
#include "util_map.h" #include "util_map.h"
#include "util_param.h" #include "util_param.h"
#include "util_string.h" #include "util_string.h"
#include "clew.h"
CCL_NAMESPACE_BEGIN CCL_NAMESPACE_BEGIN
#define CL_MEM_PTR(p) ((cl_mem)(uintptr_t)(p)) #define CL_MEM_PTR(p) ((cl_mem)(uintptr_t)(p))

@ -667,7 +667,10 @@ string OpenCLInfo::get_hardware_id(string platform_name, cl_device_id device_id)
/* Use cl_amd_device_topology extension. */ /* Use cl_amd_device_topology extension. */
cl_char topology[24]; cl_char topology[24];
if(clGetDeviceInfo(device_id, 0x4037, sizeof(topology), topology, NULL) == CL_SUCCESS && topology[0] == 1) { if(clGetDeviceInfo(device_id, 0x4037, sizeof(topology), topology, NULL) == CL_SUCCESS && topology[0] == 1) {
return string_printf("%02x:%02x.%01x", topology[21], topology[22], topology[23]); return string_printf("%02x:%02x.%01x",
(unsigned int)topology[21],
(unsigned int)topology[22],
(unsigned int)topology[23]);
} }
} }
else if(platform_name == "NVIDIA CUDA") { else if(platform_name == "NVIDIA CUDA") {
@ -675,7 +678,10 @@ string OpenCLInfo::get_hardware_id(string platform_name, cl_device_id device_id)
cl_int bus_id, slot_id; cl_int bus_id, slot_id;
if(clGetDeviceInfo(device_id, 0x4008, sizeof(cl_int), &bus_id, NULL) == CL_SUCCESS && if(clGetDeviceInfo(device_id, 0x4008, sizeof(cl_int), &bus_id, NULL) == CL_SUCCESS &&
clGetDeviceInfo(device_id, 0x4009, sizeof(cl_int), &slot_id, NULL) == CL_SUCCESS) { clGetDeviceInfo(device_id, 0x4009, sizeof(cl_int), &slot_id, NULL) == CL_SUCCESS) {
return string_printf("%02x:%02x.%01x", bus_id, slot_id>>3, slot_id & 0x7); return string_printf("%02x:%02x.%01x",
(unsigned int)(bus_id),
(unsigned int)(slot_id >> 3),
(unsigned int)(slot_id & 0x7));
} }
} }
/* No general way to get a hardware ID from OpenCL => give up. */ /* No general way to get a hardware ID from OpenCL => give up. */

@ -245,11 +245,18 @@ ccl_device float kernel_volume_equiangular_sample(Ray *ray, float3 light_P, floa
float t = ray->t; float t = ray->t;
float delta = dot((light_P - ray->P) , ray->D); float delta = dot((light_P - ray->P) , ray->D);
float D = sqrtf(len_squared(light_P - ray->P) - delta * delta); float D = safe_sqrtf(len_squared(light_P - ray->P) - delta * delta);
if(UNLIKELY(D == 0.0f)) {
*pdf = 0.0f;
return 0.0f;
}
float theta_a = -atan2f(delta, D); float theta_a = -atan2f(delta, D);
float theta_b = atan2f(t - delta, D); float theta_b = atan2f(t - delta, D);
float t_ = D * tanf((xi * theta_b) + (1 - xi) * theta_a); float t_ = D * tanf((xi * theta_b) + (1 - xi) * theta_a);
if(UNLIKELY(theta_b == theta_a)) {
*pdf = 0.0f;
return 0.0f;
}
*pdf = D / ((theta_b - theta_a) * (D * D + t_ * t_)); *pdf = D / ((theta_b - theta_a) * (D * D + t_ * t_));
return min(t, delta + t_); /* min is only for float precision errors */ return min(t, delta + t_); /* min is only for float precision errors */
@ -258,13 +265,19 @@ ccl_device float kernel_volume_equiangular_sample(Ray *ray, float3 light_P, floa
ccl_device float kernel_volume_equiangular_pdf(Ray *ray, float3 light_P, float sample_t) ccl_device float kernel_volume_equiangular_pdf(Ray *ray, float3 light_P, float sample_t)
{ {
float delta = dot((light_P - ray->P) , ray->D); float delta = dot((light_P - ray->P) , ray->D);
float D = sqrtf(len_squared(light_P - ray->P) - delta * delta); float D = safe_sqrtf(len_squared(light_P - ray->P) - delta * delta);
if(UNLIKELY(D == 0.0f)) {
return 0.0f;
}
float t = ray->t; float t = ray->t;
float t_ = sample_t - delta; float t_ = sample_t - delta;
float theta_a = -atan2f(delta, D); float theta_a = -atan2f(delta, D);
float theta_b = atan2f(t - delta, D); float theta_b = atan2f(t - delta, D);
if(UNLIKELY(theta_b == theta_a)) {
return 0.0f;
}
float pdf = D / ((theta_b - theta_a) * (D * D + t_ * t_)); float pdf = D / ((theta_b - theta_a) * (D * D + t_ * t_));
@ -958,6 +971,9 @@ ccl_device VolumeIntegrateResult kernel_volume_decoupled_scatter(
mis_weight = 2.0f*power_heuristic(pdf, distance_pdf); mis_weight = 2.0f*power_heuristic(pdf, distance_pdf);
} }
} }
if(sample_t < 1e-6f) {
return VOLUME_PATH_SCATTERED;
}
/* compute transmittance up to this step */ /* compute transmittance up to this step */
if(step != segment->steps) if(step != segment->steps)

@ -19,6 +19,7 @@
#include "scene.h" #include "scene.h"
#include "util_foreach.h" #include "util_foreach.h"
#include "util_logging.h"
#include "util_path.h" #include "util_path.h"
#include "util_progress.h" #include "util_progress.h"
#include "util_texture.h" #include "util_texture.h"
@ -476,6 +477,7 @@ template<TypeDesc::BASETYPE FileFormat,
typename DeviceType> typename DeviceType>
bool ImageManager::file_load_image(Image *img, bool ImageManager::file_load_image(Image *img,
ImageDataType type, ImageDataType type,
int texture_limit,
device_vector<DeviceType>& tex_img) device_vector<DeviceType>& tex_img)
{ {
const StorageType alpha_one = (FileFormat == TypeDesc::UINT8)? 255 : 1; const StorageType alpha_one = (FileFormat == TypeDesc::UINT8)? 255 : 1;
@ -485,11 +487,18 @@ bool ImageManager::file_load_image(Image *img,
return false; return false;
} }
/* Read RGBA pixels. */ /* Read RGBA pixels. */
StorageType *pixels = (StorageType*)tex_img.resize(width, height, depth); vector<StorageType> pixels_storage;
if(pixels == NULL) { StorageType *pixels;
return false; const size_t max_size = max(max(width, height), depth);
if(texture_limit > 0 && max_size > texture_limit) {
pixels_storage.resize(((size_t)width)*height*depth*4);
pixels = &pixels_storage[0];
}
else {
pixels = (StorageType*)tex_img.resize(width, height, depth);
} }
bool cmyk = false; bool cmyk = false;
const size_t num_pixels = ((size_t)width) * height * depth;
if(in) { if(in) {
StorageType *readpixels = pixels; StorageType *readpixels = pixels;
vector<StorageType> tmppixels; vector<StorageType> tmppixels;
@ -526,12 +535,14 @@ bool ImageManager::file_load_image(Image *img,
if(FileFormat == TypeDesc::FLOAT) { if(FileFormat == TypeDesc::FLOAT) {
builtin_image_float_pixels_cb(img->filename, builtin_image_float_pixels_cb(img->filename,
img->builtin_data, img->builtin_data,
(float*)pixels); (float*)&pixels[0],
num_pixels * components);
} }
else if(FileFormat == TypeDesc::UINT8) { else if(FileFormat == TypeDesc::UINT8) {
builtin_image_pixels_cb(img->filename, builtin_image_pixels_cb(img->filename,
img->builtin_data, img->builtin_data,
(uchar*)pixels); (uchar*)&pixels[0],
num_pixels * components);
} }
else { else {
/* TODO(dingto): Support half for ImBuf. */ /* TODO(dingto): Support half for ImBuf. */
@ -540,11 +551,10 @@ bool ImageManager::file_load_image(Image *img,
/* Check if we actually have a float4 slot, in case components == 1, /* Check if we actually have a float4 slot, in case components == 1,
* but device doesn't support single channel textures. * but device doesn't support single channel textures.
*/ */
if(type == IMAGE_DATA_TYPE_FLOAT4 || bool is_rgba = (type == IMAGE_DATA_TYPE_FLOAT4 ||
type == IMAGE_DATA_TYPE_HALF4 || type == IMAGE_DATA_TYPE_HALF4 ||
type == IMAGE_DATA_TYPE_BYTE4) type == IMAGE_DATA_TYPE_BYTE4);
{ if(is_rgba) {
size_t num_pixels = ((size_t)width) * height * depth;
if(cmyk) { if(cmyk) {
/* CMYK */ /* CMYK */
for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
@ -587,10 +597,37 @@ bool ImageManager::file_load_image(Image *img,
} }
} }
} }
if(pixels_storage.size() > 0) {
float scale_factor = 1.0f;
while(max_size * scale_factor > texture_limit) {
scale_factor *= 0.5f;
}
VLOG(1) << "Scaling image " << img->filename
<< " by a factor of " << scale_factor << ".";
vector<StorageType> scaled_pixels;
size_t scaled_width, scaled_height, scaled_depth;
util_image_resize_pixels(pixels_storage,
width, height, depth,
is_rgba ? 4 : 1,
scale_factor,
&scaled_pixels,
&scaled_width, &scaled_height, &scaled_depth);
StorageType *texture_pixels = (StorageType*)tex_img.resize(scaled_width,
scaled_height,
scaled_depth);
memcpy(texture_pixels,
&scaled_pixels[0],
scaled_pixels.size() * sizeof(StorageType));
}
return true; return true;
} }
void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot, Progress *progress) void ImageManager::device_load_image(Device *device,
DeviceScene *dscene,
Scene *scene,
ImageDataType type,
int slot,
Progress *progress)
{ {
if(progress->get_cancel()) if(progress->get_cancel())
return; return;
@ -603,6 +640,8 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
string filename = path_filename(images[type][slot]->filename); string filename = path_filename(images[type][slot]->filename);
progress->set_status("Updating Images", "Loading " + filename); progress->set_status("Updating Images", "Loading " + filename);
const int texture_limit = scene->params.texture_limit;
/* Slot assignment */ /* Slot assignment */
int flat_slot = type_index_to_flattened_slot(slot, type); int flat_slot = type_index_to_flattened_slot(slot, type);
@ -622,7 +661,11 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
device->tex_free(tex_img); device->tex_free(tex_img);
} }
if(!file_load_image<TypeDesc::FLOAT, float>(img, type, tex_img)) { if(!file_load_image<TypeDesc::FLOAT, float>(img,
type,
texture_limit,
tex_img))
{
/* on failure to load, we set a 1x1 pixels pink image */ /* on failure to load, we set a 1x1 pixels pink image */
float *pixels = (float*)tex_img.resize(1, 1); float *pixels = (float*)tex_img.resize(1, 1);
@ -648,7 +691,11 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
device->tex_free(tex_img); device->tex_free(tex_img);
} }
if(!file_load_image<TypeDesc::FLOAT, float>(img, type, tex_img)) { if(!file_load_image<TypeDesc::FLOAT, float>(img,
type,
texture_limit,
tex_img))
{
/* on failure to load, we set a 1x1 pixels pink image */ /* on failure to load, we set a 1x1 pixels pink image */
float *pixels = (float*)tex_img.resize(1, 1); float *pixels = (float*)tex_img.resize(1, 1);
@ -671,7 +718,11 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
device->tex_free(tex_img); device->tex_free(tex_img);
} }
if(!file_load_image<TypeDesc::UINT8, uchar>(img, type, tex_img)) { if(!file_load_image<TypeDesc::UINT8, uchar>(img,
type,
texture_limit,
tex_img))
{
/* on failure to load, we set a 1x1 pixels pink image */ /* on failure to load, we set a 1x1 pixels pink image */
uchar *pixels = (uchar*)tex_img.resize(1, 1); uchar *pixels = (uchar*)tex_img.resize(1, 1);
@ -697,7 +748,10 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
device->tex_free(tex_img); device->tex_free(tex_img);
} }
if(!file_load_image<TypeDesc::UINT8, uchar>(img, type, tex_img)) { if(!file_load_image<TypeDesc::UINT8, uchar>(img,
type,
texture_limit,
tex_img)) {
/* on failure to load, we set a 1x1 pixels pink image */ /* on failure to load, we set a 1x1 pixels pink image */
uchar *pixels = (uchar*)tex_img.resize(1, 1); uchar *pixels = (uchar*)tex_img.resize(1, 1);
@ -720,7 +774,10 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
device->tex_free(tex_img); device->tex_free(tex_img);
} }
if(!file_load_image<TypeDesc::HALF, half>(img, type, tex_img)) { if(!file_load_image<TypeDesc::HALF, half>(img,
type,
texture_limit,
tex_img)) {
/* on failure to load, we set a 1x1 pixels pink image */ /* on failure to load, we set a 1x1 pixels pink image */
half *pixels = (half*)tex_img.resize(1, 1); half *pixels = (half*)tex_img.resize(1, 1);
@ -746,7 +803,10 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
device->tex_free(tex_img); device->tex_free(tex_img);
} }
if(!file_load_image<TypeDesc::HALF, half>(img, type, tex_img)) { if(!file_load_image<TypeDesc::HALF, half>(img,
type,
texture_limit,
tex_img)) {
/* on failure to load, we set a 1x1 pixels pink image */ /* on failure to load, we set a 1x1 pixels pink image */
half *pixels = (half*)tex_img.resize(1, 1); half *pixels = (half*)tex_img.resize(1, 1);
@ -842,7 +902,10 @@ void ImageManager::device_free_image(Device *device, DeviceScene *dscene, ImageD
} }
} }
void ImageManager::device_update(Device *device, DeviceScene *dscene, Progress& progress) void ImageManager::device_update(Device *device,
DeviceScene *dscene,
Scene *scene,
Progress& progress)
{ {
if(!need_update) if(!need_update)
return; return;
@ -859,7 +922,14 @@ void ImageManager::device_update(Device *device, DeviceScene *dscene, Progress&
} }
else if(images[type][slot]->need_load) { else if(images[type][slot]->need_load) {
if(!osl_texture_system || images[type][slot]->builtin_data) if(!osl_texture_system || images[type][slot]->builtin_data)
pool.push(function_bind(&ImageManager::device_load_image, this, device, dscene, (ImageDataType)type, slot, &progress)); pool.push(function_bind(&ImageManager::device_load_image,
this,
device,
dscene,
scene,
(ImageDataType)type,
slot,
&progress));
} }
} }
} }
@ -874,6 +944,7 @@ void ImageManager::device_update(Device *device, DeviceScene *dscene, Progress&
void ImageManager::device_update_slot(Device *device, void ImageManager::device_update_slot(Device *device,
DeviceScene *dscene, DeviceScene *dscene,
Scene *scene,
int flat_slot, int flat_slot,
Progress *progress) Progress *progress)
{ {
@ -890,6 +961,7 @@ void ImageManager::device_update_slot(Device *device,
if(!osl_texture_system || image->builtin_data) if(!osl_texture_system || image->builtin_data)
device_load_image(device, device_load_image(device,
dscene, dscene,
scene,
type, type,
slot, slot,
progress); progress);

@ -30,6 +30,7 @@ CCL_NAMESPACE_BEGIN
class Device; class Device;
class DeviceScene; class DeviceScene;
class Progress; class Progress;
class Scene;
class ImageManager { class ImageManager {
public: public:
@ -67,8 +68,15 @@ public:
ExtensionType extension); ExtensionType extension);
ImageDataType get_image_metadata(const string& filename, void *builtin_data, bool& is_linear); ImageDataType get_image_metadata(const string& filename, void *builtin_data, bool& is_linear);
void device_update(Device *device, DeviceScene *dscene, Progress& progress); void device_update(Device *device,
void device_update_slot(Device *device, DeviceScene *dscene, int flat_slot, Progress *progress); DeviceScene *dscene,
Scene *scene,
Progress& progress);
void device_update_slot(Device *device,
DeviceScene *dscene,
Scene *scene,
int flat_slot,
Progress *progress);
void device_free(Device *device, DeviceScene *dscene); void device_free(Device *device, DeviceScene *dscene);
void device_free_builtin(Device *device, DeviceScene *dscene); void device_free_builtin(Device *device, DeviceScene *dscene);
@ -78,9 +86,25 @@ public:
bool need_update; bool need_update;
function<void(const string &filename, void *data, bool &is_float, int &width, int &height, int &depth, int &channels)> builtin_image_info_cb; /* NOTE: Here pixels_size is a size of storage, which equals to
function<bool(const string &filename, void *data, unsigned char *pixels)> builtin_image_pixels_cb; * width * height * depth.
function<bool(const string &filename, void *data, float *pixels)> builtin_image_float_pixels_cb; * Use this to avoid some nasty memory corruptions.
*/
function<void(const string &filename,
void *data,
bool &is_float,
int &width,
int &height,
int &depth,
int &channels)> builtin_image_info_cb;
function<bool(const string &filename,
void *data,
unsigned char *pixels,
const size_t pixels_size)> builtin_image_pixels_cb;
function<bool(const string &filename,
void *data,
float *pixels,
const size_t pixels_size)> builtin_image_float_pixels_cb;
struct Image { struct Image {
string filename; string filename;
@ -114,6 +138,7 @@ private:
typename DeviceType> typename DeviceType>
bool file_load_image(Image *img, bool file_load_image(Image *img,
ImageDataType type, ImageDataType type,
int texture_limit,
device_vector<DeviceType>& tex_img); device_vector<DeviceType>& tex_img);
int type_index_to_flattened_slot(int slot, ImageDataType type); int type_index_to_flattened_slot(int slot, ImageDataType type);
@ -122,10 +147,20 @@ private:
uint8_t pack_image_options(ImageDataType type, size_t slot); uint8_t pack_image_options(ImageDataType type, size_t slot);
void device_load_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot, Progress *progess); void device_load_image(Device *device,
void device_free_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot); DeviceScene *dscene,
Scene *scene,
ImageDataType type,
int slot,
Progress *progess);
void device_free_image(Device *device,
DeviceScene *dscene,
ImageDataType type,
int slot);
void device_pack_images(Device *device, DeviceScene *dscene, Progress& progess); void device_pack_images(Device *device,
DeviceScene *dscene,
Progress& progess);
}; };
CCL_NAMESPACE_END CCL_NAMESPACE_END

@ -1084,7 +1084,7 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
} }
/* terminator */ /* terminator */
for(int i = 0; i < ATTR_PRIM_TYPES; i++) { for(int j = 0; j < ATTR_PRIM_TYPES; j++) {
attr_map[index].x = ATTR_STD_NONE; attr_map[index].x = ATTR_STD_NONE;
attr_map[index].y = 0; attr_map[index].y = 0;
attr_map[index].z = 0; attr_map[index].z = 0;
@ -1665,6 +1665,7 @@ void MeshManager::device_update_displacement_images(Device *device,
*/ */
image_manager->device_update(device, image_manager->device_update(device,
dscene, dscene,
scene,
progress); progress);
return; return;
} }
@ -1682,6 +1683,7 @@ void MeshManager::device_update_displacement_images(Device *device,
image_manager, image_manager,
device, device,
dscene, dscene,
scene,
slot, slot,
&progress)); &progress));
} }

@ -3993,7 +3993,7 @@ NODE_DEFINE(SeparateRGBNode)
SOCKET_IN_COLOR(color, "Image", make_float3(0.0f, 0.0f, 0.0f)); SOCKET_IN_COLOR(color, "Image", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_OUT_FLOAT(g, "R"); SOCKET_OUT_FLOAT(r, "R");
SOCKET_OUT_FLOAT(g, "G"); SOCKET_OUT_FLOAT(g, "G");
SOCKET_OUT_FLOAT(b, "B"); SOCKET_OUT_FLOAT(b, "B");

@ -187,7 +187,7 @@ void Scene::device_update(Device *device_, Progress& progress)
if(progress.get_cancel() || device->have_error()) return; if(progress.get_cancel() || device->have_error()) return;
progress.set_status("Updating Images"); progress.set_status("Updating Images");
image_manager->device_update(device, &dscene, progress); image_manager->device_update(device, &dscene, this, progress);
if(progress.get_cancel() || device->have_error()) return; if(progress.get_cancel() || device->have_error()) return;

@ -145,6 +145,7 @@ public:
bool use_bvh_unaligned_nodes; bool use_bvh_unaligned_nodes;
bool use_qbvh; bool use_qbvh;
bool persistent_data; bool persistent_data;
int texture_limit;
SceneParams() SceneParams()
{ {
@ -154,6 +155,7 @@ public:
use_bvh_unaligned_nodes = true; use_bvh_unaligned_nodes = true;
use_qbvh = false; use_qbvh = false;
persistent_data = false; persistent_data = false;
texture_limit = 0;
} }
bool modified(const SceneParams& params) bool modified(const SceneParams& params)
@ -162,7 +164,8 @@ public:
&& use_bvh_spatial_split == params.use_bvh_spatial_split && use_bvh_spatial_split == params.use_bvh_spatial_split
&& use_bvh_unaligned_nodes == params.use_bvh_unaligned_nodes && use_bvh_unaligned_nodes == params.use_bvh_unaligned_nodes
&& use_qbvh == params.use_qbvh && use_qbvh == params.use_qbvh
&& persistent_data == params.persistent_data); } && persistent_data == params.persistent_data
&& texture_limit == params.texture_limit); }
}; };
/* Scene */ /* Scene */

@ -71,14 +71,13 @@ void SVMShaderManager::device_update_shader(Scene *scene,
scene->light_manager->need_update = true; scene->light_manager->need_update = true;
} }
/* We only calculate offset and do re-allocation from the locked block, /* The copy needs to be done inside the lock, if another thread resizes the array
* actual copy we do after the lock is releases to hopefully gain some * while memcpy is running, it'll be copying into possibly invalid/freed ram.
* percent of performance.
*/ */
nodes_lock_.lock(); nodes_lock_.lock();
size_t global_nodes_size = global_svm_nodes->size(); size_t global_nodes_size = global_svm_nodes->size();
global_svm_nodes->resize(global_nodes_size + svm_nodes.size()); global_svm_nodes->resize(global_nodes_size + svm_nodes.size());
nodes_lock_.unlock();
/* Offset local SVM nodes to a global address space. */ /* Offset local SVM nodes to a global address space. */
int4& jump_node = global_svm_nodes->at(shader->id); int4& jump_node = global_svm_nodes->at(shader->id);
jump_node.y = svm_nodes[0].y + global_nodes_size - 1; jump_node.y = svm_nodes[0].y + global_nodes_size - 1;
@ -88,6 +87,7 @@ void SVMShaderManager::device_update_shader(Scene *scene,
memcpy(&global_svm_nodes->at(global_nodes_size), memcpy(&global_svm_nodes->at(global_nodes_size),
&svm_nodes[1], &svm_nodes[1],
sizeof(int4) * (svm_nodes.size() - 1)); sizeof(int4) * (svm_nodes.size() - 1));
nodes_lock_.unlock();
} }
void SVMShaderManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) void SVMShaderManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)

@ -45,6 +45,7 @@ set(SRC_HEADERS
util_half.h util_half.h
util_hash.h util_hash.h
util_image.h util_image.h
util_image_impl.h
util_list.h util_list.h
util_logging.h util_logging.h
util_map.h util_map.h

@ -21,11 +21,25 @@
#include <OpenImageIO/imageio.h> #include <OpenImageIO/imageio.h>
#include "util_vector.h"
CCL_NAMESPACE_BEGIN CCL_NAMESPACE_BEGIN
OIIO_NAMESPACE_USING OIIO_NAMESPACE_USING
template<typename T>
void util_image_resize_pixels(const vector<T>& input_pixels,
const size_t input_width,
const size_t input_height,
const size_t input_depth,
const size_t components,
vector<T> *output_pixels,
size_t *output_width,
size_t *output_height,
size_t *output_depth);
CCL_NAMESPACE_END CCL_NAMESPACE_END
#endif /* __UTIL_IMAGE_H__ */ #endif /* __UTIL_IMAGE_H__ */
#include "util_image_impl.h"

@ -0,0 +1,168 @@
/*
* Copyright 2011-2016 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.
*/
#ifndef __UTIL_IMAGE_IMPL_H__
#define __UTIL_IMAGE_IMPL_H__
#include "util_algorithm.h"
#include "util_debug.h"
#include "util_image.h"
CCL_NAMESPACE_BEGIN
namespace {
template<typename T>
const T *util_image_read(const vector<T>& pixels,
const size_t width,
const size_t height,
const size_t /*depth*/,
const size_t components,
const size_t x, const size_t y, const size_t z) {
const size_t index = ((size_t)z * (width * height) +
(size_t)y * width +
(size_t)x) * components;
return &pixels[index];
}
template<typename T>
void util_image_downscale_sample(const vector<T>& pixels,
const size_t width,
const size_t height,
const size_t depth,
const size_t components,
const size_t kernel_size,
const float x,
const float y,
const float z,
T *result)
{
assert(components <= 4);
const size_t ix = (size_t)x,
iy = (size_t)y,
iz = (size_t)z;
/* TODO(sergey): Support something smarter than box filer. */
float accum[4] = {0};
size_t count = 0;
for(size_t dz = 0; dz < kernel_size; ++dz) {
for(size_t dy = 0; dy < kernel_size; ++dy) {
for(size_t dx = 0; dx < kernel_size; ++dx) {
const size_t nx = ix + dx,
ny = iy + dy,
nz = iz + dz;
if(nx >= width || ny >= height || nz >= depth) {
continue;
}
const T *pixel = util_image_read(pixels,
width, height, depth,
components,
nx, ny, nz);
for(size_t k = 0; k < components; ++k) {
accum[k] += pixel[k];
}
++count;
}
}
}
const float inv_count = 1.0f / (float)count;
for(size_t k = 0; k < components; ++k) {
result[k] = T(accum[k] * inv_count);
}
}
template<typename T>
void util_image_downscale_pixels(const vector<T>& input_pixels,
const size_t input_width,
const size_t input_height,
const size_t input_depth,
const size_t components,
const float inv_scale_factor,
const size_t output_width,
const size_t output_height,
const size_t output_depth,
vector<T> *output_pixels)
{
const size_t kernel_size = (size_t)(inv_scale_factor + 0.5f);
for(size_t z = 0; z < output_depth; ++z) {
for(size_t y = 0; y < output_height; ++y) {
for(size_t x = 0; x < output_width; ++x) {
const float input_x = (float)x * inv_scale_factor,
input_y = (float)y * inv_scale_factor,
input_z = (float)z * inv_scale_factor;
const size_t output_index =
(z * output_width * output_height +
y * output_width + x) * components;
util_image_downscale_sample(input_pixels,
input_width, input_height, input_depth,
components,
kernel_size,
input_x, input_y, input_z,
&output_pixels->at(output_index));
}
}
}
}
} /* namespace */
template<typename T>
void util_image_resize_pixels(const vector<T>& input_pixels,
const size_t input_width,
const size_t input_height,
const size_t input_depth,
const size_t components,
const float scale_factor,
vector<T> *output_pixels,
size_t *output_width,
size_t *output_height,
size_t *output_depth)
{
/* Early output for case when no scaling is applied. */
if(scale_factor == 1.0f) {
*output_width = input_width;
*output_height = input_height;
*output_depth = input_depth;
*output_pixels = input_pixels;
return;
}
/* First of all, we calculate output image dimensions.
* We clamp them to be 1 pixel at least so we do not generate degenerate
* image.
*/
*output_width = max((size_t)((float)input_width * scale_factor), (size_t)1);
*output_height = max((size_t)((float)input_height * scale_factor), (size_t)1);
*output_depth = max((size_t)((float)input_depth * scale_factor), (size_t)1);
/* Prepare pixel storage for the result. */
const size_t num_output_pixels = ((*output_width) *
(*output_height) *
(*output_depth)) * components;
output_pixels->resize(num_output_pixels);
if(scale_factor < 1.0f) {
const float inv_scale_factor = 1.0f / scale_factor;
util_image_downscale_pixels(input_pixels,
input_width, input_height, input_depth,
components,
inv_scale_factor,
*output_width, *output_height, *output_depth,
output_pixels);
} else {
/* TODO(sergey): Needs implementation. */
}
}
CCL_NAMESPACE_END
#endif /* __UTIL_IMAGE_IMPL_H__ */

@ -229,7 +229,7 @@ __forceinline int __btr(int v, int i) {
int r = 0; asm ("btr %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags"); return r; int r = 0; asm ("btr %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags"); return r;
} }
#if defined(__KERNEL_64_BIT__) || defined(__APPLE__) #if (defined(__KERNEL_64_BIT__) || defined(__APPLE__)) && !(defined(__ILP32__) && defined(__x86_64__))
__forceinline size_t __bsf(size_t v) { __forceinline size_t __bsf(size_t v) {
size_t r = 0; asm ("bsf %1,%0" : "=r"(r) : "r"(v)); return r; size_t r = 0; asm ("bsf %1,%0" : "=r"(r) : "r"(v)); return r;
} }
@ -271,7 +271,7 @@ __forceinline unsigned int bitscan(unsigned int v) {
#endif #endif
} }
#if defined(__KERNEL_64_BIT__) || defined(__APPLE__) #if (defined(__KERNEL_64_BIT__) || defined(__APPLE__)) && !(defined(__ILP32__) && defined(__x86_64__))
__forceinline size_t bitscan(size_t v) { __forceinline size_t bitscan(size_t v) {
#if defined(__KERNEL_AVX2__) #if defined(__KERNEL_AVX2__)
#if defined(__KERNEL_64_BIT__) #if defined(__KERNEL_64_BIT__)
@ -313,7 +313,7 @@ __forceinline unsigned int __bscf(unsigned int& v)
return i; return i;
} }
#if defined(__KERNEL_64_BIT__) || defined(__APPLE__) #if (defined(__KERNEL_64_BIT__) || defined(__APPLE__)) && !(defined(__ILP32__) && defined(__x86_64__))
__forceinline size_t __bscf(size_t& v) __forceinline size_t __bscf(size_t& v)
{ {
size_t i = bitscan(v); size_t i = bitscan(v);

@ -89,6 +89,22 @@ int system_cpu_thread_count()
return count; return count;
} }
unsigned short system_cpu_process_groups(unsigned short max_groups,
unsigned short *groups)
{
#ifdef _WIN32
unsigned short group_count = max_groups;
if(!GetProcessGroupAffinity(GetCurrentProcess(), &group_count, groups)) {
return 0;
}
return group_count;
#else
(void) max_groups;
(void) groups;
return 0;
#endif
}
#if !defined(_WIN32) || defined(FREE_WINDOWS) #if !defined(_WIN32) || defined(FREE_WINDOWS)
static void __cpuid(int data[4], int selector) static void __cpuid(int data[4], int selector)
{ {

@ -30,6 +30,10 @@ int system_cpu_group_thread_count(int group);
/* Get total number of threads in all groups. */ /* Get total number of threads in all groups. */
int system_cpu_thread_count(); int system_cpu_thread_count();
/* Get current process groups. */
unsigned short system_cpu_process_groups(unsigned short max_groups,
unsigned short *grpups);
string system_cpu_brand_string(); string system_cpu_brand_string();
int system_cpu_bits(); int system_cpu_bits();
bool system_cpu_support_sse2(); bool system_cpu_support_sse2();

@ -195,7 +195,8 @@ void TaskScheduler::init(int num_threads)
if(users == 0) { if(users == 0) {
do_exit = false; do_exit = false;
if(num_threads == 0) { const bool use_auto_threads = (num_threads == 0);
if(use_auto_threads) {
/* automatic number of threads */ /* automatic number of threads */
num_threads = system_cpu_thread_count(); num_threads = system_cpu_thread_count();
} }
@ -204,7 +205,18 @@ void TaskScheduler::init(int num_threads)
/* launch threads that will be waiting for work */ /* launch threads that will be waiting for work */
threads.resize(num_threads); threads.resize(num_threads);
int num_groups = system_cpu_group_count(); const int num_groups = system_cpu_group_count();
unsigned short num_process_groups;
vector<unsigned short> process_groups;
int current_group_threads;
if(num_groups > 1) {
process_groups.resize(num_groups);
num_process_groups = system_cpu_process_groups(num_groups,
&process_groups[0]);
if(num_process_groups == 1) {
current_group_threads = system_cpu_group_thread_count(process_groups[0]);
}
}
int thread_index = 0; int thread_index = 0;
for(int group = 0; group < num_groups; ++group) { for(int group = 0; group < num_groups; ++group) {
/* NOTE: That's not really efficient from threading point of view, /* NOTE: That's not really efficient from threading point of view,
@ -218,9 +230,25 @@ void TaskScheduler::init(int num_threads)
group_thread < num_group_threads && thread_index < threads.size(); group_thread < num_group_threads && thread_index < threads.size();
++group_thread, ++thread_index) ++group_thread, ++thread_index)
{ {
/* NOTE: Thread group of -1 means we would not force thread affinity. */
int thread_group;
if(num_groups == 1) {
/* Use default affinity if there's only one CPU group in the system. */
thread_group = -1;
}
else if(use_auto_threads &&
num_process_groups == 1 &&
num_threads <= current_group_threads)
{
/* If we fit into curent CPU group we also don't force any affinity. */
thread_group = -1;
}
else {
thread_group = group;
}
threads[thread_index] = new thread(function_bind(&TaskScheduler::thread_run, threads[thread_index] = new thread(function_bind(&TaskScheduler::thread_run,
thread_index + 1), thread_index + 1),
group); thread_group);
} }
} }
} }

@ -28,6 +28,7 @@ CCL_NAMESPACE_BEGIN
tGetActiveProcessorGroupCount *GetActiveProcessorGroupCount; tGetActiveProcessorGroupCount *GetActiveProcessorGroupCount;
tGetActiveProcessorCount *GetActiveProcessorCount; tGetActiveProcessorCount *GetActiveProcessorCount;
tSetThreadGroupAffinity *SetThreadGroupAffinity; tSetThreadGroupAffinity *SetThreadGroupAffinity;
tGetProcessGroupAffinity *GetProcessGroupAffinity;
#endif #endif
static WORD GetActiveProcessorGroupCount_stub() static WORD GetActiveProcessorGroupCount_stub()
@ -50,6 +51,18 @@ static BOOL SetThreadGroupAffinity_stub(
return TRUE; return TRUE;
} }
static BOOL GetProcessGroupAffinity_stub(HANDLE hProcess,
PUSHORT GroupCount,
PUSHORT GroupArray)
{
if(*GroupCount < 1) {
return FALSE;
}
*GroupCount = 1;
GroupArray[0] = 0;
return TRUE;
}
static bool supports_numa() static bool supports_numa()
{ {
#ifndef _M_X64 #ifndef _M_X64
@ -72,6 +85,7 @@ void util_windows_init_numa_groups()
GetActiveProcessorGroupCount = GetActiveProcessorGroupCount_stub; GetActiveProcessorGroupCount = GetActiveProcessorGroupCount_stub;
GetActiveProcessorCount = GetActiveProcessorCount_stub; GetActiveProcessorCount = GetActiveProcessorCount_stub;
SetThreadGroupAffinity = SetThreadGroupAffinity_stub; SetThreadGroupAffinity = SetThreadGroupAffinity_stub;
GetProcessGroupAffinity = GetProcessGroupAffinity_stub;
return; return;
} }
HMODULE kernel = GetModuleHandleA("kernel32.dll"); HMODULE kernel = GetModuleHandleA("kernel32.dll");
@ -79,6 +93,7 @@ void util_windows_init_numa_groups()
READ_SYMBOL(GetActiveProcessorGroupCount); READ_SYMBOL(GetActiveProcessorGroupCount);
READ_SYMBOL(GetActiveProcessorCount); READ_SYMBOL(GetActiveProcessorCount);
READ_SYMBOL(SetThreadGroupAffinity); READ_SYMBOL(SetThreadGroupAffinity);
READ_SYMBOL(GetProcessGroupAffinity);
# undef READ_SUMBOL # undef READ_SUMBOL
#endif #endif
} }

@ -39,10 +39,14 @@ typedef DWORD tGetActiveProcessorCount(WORD GroupNumber);
typedef BOOL tSetThreadGroupAffinity(HANDLE hThread, typedef BOOL tSetThreadGroupAffinity(HANDLE hThread,
const GROUP_AFFINITY *GroupAffinity, const GROUP_AFFINITY *GroupAffinity,
PGROUP_AFFINITY PreviousGroupAffinity); PGROUP_AFFINITY PreviousGroupAffinity);
typedef BOOL tGetProcessGroupAffinity(HANDLE hProcess,
PUSHORT GroupCount,
PUSHORT GroupArray);
extern tGetActiveProcessorGroupCount *GetActiveProcessorGroupCount; extern tGetActiveProcessorGroupCount *GetActiveProcessorGroupCount;
extern tGetActiveProcessorCount *GetActiveProcessorCount; extern tGetActiveProcessorCount *GetActiveProcessorCount;
extern tSetThreadGroupAffinity *SetThreadGroupAffinity; extern tSetThreadGroupAffinity *SetThreadGroupAffinity;
extern tGetProcessGroupAffinity *GetProcessGroupAffinity;
#endif #endif
/* Make sure NUMA and processor groups API is initialized. */ /* Make sure NUMA and processor groups API is initialized. */

@ -353,7 +353,7 @@ GHOST_WindowWin32::~GHOST_WindowWin32()
// Release our reference of the DropTarget and it will delete itself eventually. // Release our reference of the DropTarget and it will delete itself eventually.
m_dropTarget->Release(); m_dropTarget->Release();
} }
::SetWindowLongPtr(m_hWnd, GWLP_USERDATA, NULL);
::DestroyWindow(m_hWnd); ::DestroyWindow(m_hWnd);
m_hWnd = 0; m_hWnd = 0;
} }

@ -861,24 +861,32 @@ void GHOST_WindowX11::icccmSetState(int state)
int GHOST_WindowX11::icccmGetState(void) const int GHOST_WindowX11::icccmGetState(void) const
{ {
Atom *prop_ret; struct {
CARD32 state;
XID icon;
} *prop_ret;
unsigned long bytes_after, num_ret; unsigned long bytes_after, num_ret;
Atom type_ret; Atom type_ret;
int format_ret, st; int ret, format_ret;
CARD32 st;
prop_ret = NULL; prop_ret = NULL;
st = XGetWindowProperty( ret = XGetWindowProperty(
m_display, m_window, m_system->m_atom.WM_STATE, 0, 2, m_display, m_window, m_system->m_atom.WM_STATE, 0, 2,
False, m_system->m_atom.WM_STATE, &type_ret, False, m_system->m_atom.WM_STATE, &type_ret,
&format_ret, &num_ret, &bytes_after, ((unsigned char **)&prop_ret)); &format_ret, &num_ret, &bytes_after, ((unsigned char **)&prop_ret));
if ((st == Success) && (prop_ret) && (num_ret == 2)) if ((ret == Success) && (prop_ret != NULL) && (num_ret == 2)) {
st = prop_ret[0]; st = prop_ret->state;
else }
else {
st = NormalState; st = NormalState;
}
if (prop_ret) if (prop_ret) {
XFree(prop_ret); XFree(prop_ret);
return (st); }
return st;
} }
void GHOST_WindowX11::netwmMaximized(bool set) void GHOST_WindowX11::netwmMaximized(bool set)

@ -77,7 +77,8 @@ int FallbackImpl::configGetNumColorSpaces(OCIO_ConstConfigRcPtr * /*config*/)
return 2; return 2;
} }
const char *FallbackImpl::configGetColorSpaceNameByIndex(OCIO_ConstConfigRcPtr * /*config*/, int index) const char *FallbackImpl::configGetColorSpaceNameByIndex(OCIO_ConstConfigRcPtr * /*config*/,
int index)
{ {
if (index == 0) if (index == 0)
return "Linear"; return "Linear";
@ -87,7 +88,8 @@ const char *FallbackImpl::configGetColorSpaceNameByIndex(OCIO_ConstConfigRcPtr *
return NULL; return NULL;
} }
OCIO_ConstColorSpaceRcPtr *FallbackImpl::configGetColorSpace(OCIO_ConstConfigRcPtr * /*config*/, const char *name) OCIO_ConstColorSpaceRcPtr *FallbackImpl::configGetColorSpace(OCIO_ConstConfigRcPtr * /*config*/,
const char *name)
{ {
if (strcmp(name, "scene_linear") == 0) if (strcmp(name, "scene_linear") == 0)
return COLORSPACE_LINEAR; return COLORSPACE_LINEAR;
@ -109,15 +111,17 @@ OCIO_ConstColorSpaceRcPtr *FallbackImpl::configGetColorSpace(OCIO_ConstConfigRcP
return NULL; return NULL;
} }
int FallbackImpl::configGetIndexForColorSpace(OCIO_ConstConfigRcPtr *config, const char *name) int FallbackImpl::configGetIndexForColorSpace(OCIO_ConstConfigRcPtr *config,
const char *name)
{ {
OCIO_ConstColorSpaceRcPtr *cs = configGetColorSpace(config, name); OCIO_ConstColorSpaceRcPtr *cs = configGetColorSpace(config, name);
if (cs == COLORSPACE_LINEAR) if (cs == COLORSPACE_LINEAR) {
return 0; return 0;
else if (cs == COLORSPACE_SRGB) }
else if (cs == COLORSPACE_SRGB) {
return 1; return 1;
}
return -1; return -1;
} }
@ -131,44 +135,51 @@ int FallbackImpl::configGetNumDisplays(OCIO_ConstConfigRcPtr * /*config*/)
return 1; return 1;
} }
const char *FallbackImpl::configGetDisplay(OCIO_ConstConfigRcPtr * /*config*/, int index) const char *FallbackImpl::configGetDisplay(OCIO_ConstConfigRcPtr * /*config*/,
int index)
{ {
if (index == 0) if (index == 0) {
return "sRGB"; return "sRGB";
}
return NULL; return NULL;
} }
const char *FallbackImpl::configGetDefaultView(OCIO_ConstConfigRcPtr * /*config*/, const char * /*display*/) const char *FallbackImpl::configGetDefaultView(OCIO_ConstConfigRcPtr * /*config*/,
const char * /*display*/)
{ {
return "Default"; return "Default";
} }
int FallbackImpl::configGetNumViews(OCIO_ConstConfigRcPtr * /*config*/, const char * /*display*/) int FallbackImpl::configGetNumViews(OCIO_ConstConfigRcPtr * /*config*/,
const char * /*display*/)
{ {
return 1; return 1;
} }
const char *FallbackImpl::configGetView(OCIO_ConstConfigRcPtr * /*config*/, const char * /*display*/, int index) const char *FallbackImpl::configGetView(OCIO_ConstConfigRcPtr * /*config*/,
const char * /*display*/, int index)
{ {
if (index == 0) if (index == 0) {
return "Default"; return "Default";
}
return NULL; return NULL;
} }
const char *FallbackImpl::configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr * /*config*/, const char * /*display*/, const char * /*view*/) const char *FallbackImpl::configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr * /*config*/,
const char * /*display*/,
const char * /*view*/)
{ {
return "sRGB"; return "sRGB";
} }
void FallbackImpl::configGetDefaultLumaCoefs(OCIO_ConstConfigRcPtr * /*config*/, float *rgb) void FallbackImpl::configGetDefaultLumaCoefs(OCIO_ConstConfigRcPtr * /*config*/,
float *rgb)
{ {
/* Here we simply use the older Blender assumed primaries of /* Here we simply use the older Blender assumed primaries of
* ITU-BT.709 / sRGB, or 0.2126729 0.7151522 0.0721750. Brute * ITU-BT.709 / sRGB, or 0.2126729 0.7151522 0.0721750. Brute
* force stupid, but only plausible option given no color management * force stupid, but only plausible option given no color management
* system in place. * system in place.
*/ */
rgb[0] = 0.2126f; rgb[0] = 0.2126f;
rgb[1] = 0.7152f; rgb[1] = 0.7152f;
@ -180,12 +191,14 @@ int FallbackImpl::configGetNumLooks(OCIO_ConstConfigRcPtr * /*config*/)
return 0; return 0;
} }
const char *FallbackImpl::configGetLookNameByIndex(OCIO_ConstConfigRcPtr * /*config*/, int /*index*/) const char *FallbackImpl::configGetLookNameByIndex(OCIO_ConstConfigRcPtr * /*config*/,
int /*index*/)
{ {
return ""; return "";
} }
OCIO_ConstLookRcPtr *FallbackImpl::configGetLook(OCIO_ConstConfigRcPtr * /*config*/, const char * /*name*/) OCIO_ConstLookRcPtr *FallbackImpl::configGetLook(OCIO_ConstConfigRcPtr * /*config*/,
const char * /*name*/)
{ {
return NULL; return NULL;
} }
@ -213,25 +226,30 @@ void FallbackImpl::colorSpaceRelease(OCIO_ConstColorSpaceRcPtr * /*cs*/)
{ {
} }
OCIO_ConstProcessorRcPtr *FallbackImpl::configGetProcessorWithNames(OCIO_ConstConfigRcPtr *config, const char *srcName, const char *dstName) OCIO_ConstProcessorRcPtr *FallbackImpl::configGetProcessorWithNames(
OCIO_ConstConfigRcPtr *config,
const char *srcName,
const char *dstName)
{ {
OCIO_ConstColorSpaceRcPtr *cs_src = configGetColorSpace(config, srcName); OCIO_ConstColorSpaceRcPtr *cs_src = configGetColorSpace(config, srcName);
OCIO_ConstColorSpaceRcPtr *cs_dst = configGetColorSpace(config, dstName); OCIO_ConstColorSpaceRcPtr *cs_dst = configGetColorSpace(config, dstName);
if (cs_src == COLORSPACE_LINEAR && cs_dst == COLORSPACE_SRGB) {
if (cs_src == COLORSPACE_LINEAR && cs_dst == COLORSPACE_SRGB)
return PROCESSOR_LINEAR_TO_SRGB; return PROCESSOR_LINEAR_TO_SRGB;
else if (cs_src == COLORSPACE_SRGB && cs_dst == COLORSPACE_LINEAR) }
else if (cs_src == COLORSPACE_SRGB && cs_dst == COLORSPACE_LINEAR) {
return PROCESSOR_SRGB_TO_LINEAR; return PROCESSOR_SRGB_TO_LINEAR;
}
return 0; return 0;
} }
OCIO_ConstProcessorRcPtr *FallbackImpl::configGetProcessor(OCIO_ConstConfigRcPtr * /*config*/, OCIO_ConstTransformRcPtr *tfm) OCIO_ConstProcessorRcPtr *FallbackImpl::configGetProcessor(OCIO_ConstConfigRcPtr * /*config*/,
OCIO_ConstTransformRcPtr *tfm)
{ {
return (OCIO_ConstProcessorRcPtr*)tfm; return (OCIO_ConstProcessorRcPtr*)tfm;
} }
void FallbackImpl::processorApply(OCIO_ConstProcessorRcPtr *processor, OCIO_PackedImageDesc *img) void FallbackImpl::processorApply(OCIO_ConstProcessorRcPtr *processor,
OCIO_PackedImageDesc *img)
{ {
/* OCIO_TODO stride not respected, channels must be 3 or 4 */ /* OCIO_TODO stride not respected, channels must be 3 or 4 */
OCIO_PackedImageDescription *desc = (OCIO_PackedImageDescription*)img; OCIO_PackedImageDescription *desc = (OCIO_PackedImageDescription*)img;
@ -253,7 +271,8 @@ void FallbackImpl::processorApply(OCIO_ConstProcessorRcPtr *processor, OCIO_Pack
} }
} }
void FallbackImpl::processorApply_predivide(OCIO_ConstProcessorRcPtr *processor, OCIO_PackedImageDesc *img) void FallbackImpl::processorApply_predivide(OCIO_ConstProcessorRcPtr *processor,
OCIO_PackedImageDesc *img)
{ {
/* OCIO_TODO stride not respected, channels must be 3 or 4 */ /* OCIO_TODO stride not respected, channels must be 3 or 4 */
OCIO_PackedImageDescription *desc = (OCIO_PackedImageDescription*)img; OCIO_PackedImageDescription *desc = (OCIO_PackedImageDescription*)img;
@ -275,15 +294,19 @@ void FallbackImpl::processorApply_predivide(OCIO_ConstProcessorRcPtr *processor,
} }
} }
void FallbackImpl::processorApplyRGB(OCIO_ConstProcessorRcPtr *processor, float *pixel) void FallbackImpl::processorApplyRGB(OCIO_ConstProcessorRcPtr *processor,
float *pixel)
{ {
if (processor == PROCESSOR_LINEAR_TO_SRGB) if (processor == PROCESSOR_LINEAR_TO_SRGB) {
linearrgb_to_srgb_v3_v3(pixel, pixel); linearrgb_to_srgb_v3_v3(pixel, pixel);
else if (processor == PROCESSOR_SRGB_TO_LINEAR) }
else if (processor == PROCESSOR_SRGB_TO_LINEAR) {
srgb_to_linearrgb_v3_v3(pixel, pixel); srgb_to_linearrgb_v3_v3(pixel, pixel);
}
} }
void FallbackImpl::processorApplyRGBA(OCIO_ConstProcessorRcPtr *processor, float *pixel) void FallbackImpl::processorApplyRGBA(OCIO_ConstProcessorRcPtr *processor,
float *pixel)
{ {
if (processor == PROCESSOR_LINEAR_TO_SRGB) if (processor == PROCESSOR_LINEAR_TO_SRGB)
linearrgb_to_srgb_v4(pixel, pixel); linearrgb_to_srgb_v4(pixel, pixel);
@ -291,7 +314,8 @@ void FallbackImpl::processorApplyRGBA(OCIO_ConstProcessorRcPtr *processor, float
srgb_to_linearrgb_v4(pixel, pixel); srgb_to_linearrgb_v4(pixel, pixel);
} }
void FallbackImpl::processorApplyRGBA_predivide(OCIO_ConstProcessorRcPtr *processor, float *pixel) void FallbackImpl::processorApplyRGBA_predivide(OCIO_ConstProcessorRcPtr *processor,
float *pixel)
{ {
if (pixel[3] == 1.0f || pixel[3] == 0.0f) { if (pixel[3] == 1.0f || pixel[3] == 0.0f) {
processorApplyRGBA(processor, pixel); processorApplyRGBA(processor, pixel);
@ -320,11 +344,12 @@ void FallbackImpl::processorRelease(OCIO_ConstProcessorRcPtr * /*p*/)
const char *FallbackImpl::colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs) const char *FallbackImpl::colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs)
{ {
if (cs == COLORSPACE_LINEAR) if (cs == COLORSPACE_LINEAR) {
return "Linear"; return "Linear";
else if (cs == COLORSPACE_SRGB) }
else if (cs == COLORSPACE_SRGB) {
return "sRGB"; return "sRGB";
}
return NULL; return NULL;
} }
@ -343,31 +368,38 @@ OCIO_DisplayTransformRcPtr *FallbackImpl::createDisplayTransform(void)
return (OCIO_DisplayTransformRcPtr*)PROCESSOR_LINEAR_TO_SRGB; return (OCIO_DisplayTransformRcPtr*)PROCESSOR_LINEAR_TO_SRGB;
} }
void FallbackImpl::displayTransformSetInputColorSpaceName(OCIO_DisplayTransformRcPtr * /*dt*/, const char * /*name*/) void FallbackImpl::displayTransformSetInputColorSpaceName(OCIO_DisplayTransformRcPtr * /*dt*/,
const char * /*name*/)
{ {
} }
void FallbackImpl::displayTransformSetDisplay(OCIO_DisplayTransformRcPtr * /*dt*/, const char * /*name*/) void FallbackImpl::displayTransformSetDisplay(OCIO_DisplayTransformRcPtr * /*dt*/,
const char * /*name*/)
{ {
} }
void FallbackImpl::displayTransformSetView(OCIO_DisplayTransformRcPtr * /*dt*/, const char * /*name*/) void FallbackImpl::displayTransformSetView(OCIO_DisplayTransformRcPtr * /*dt*/,
const char * /*name*/)
{ {
} }
void FallbackImpl::displayTransformSetDisplayCC(OCIO_DisplayTransformRcPtr * /*dt*/, OCIO_ConstTransformRcPtr * /*et*/) void FallbackImpl::displayTransformSetDisplayCC(OCIO_DisplayTransformRcPtr * /*dt*/,
OCIO_ConstTransformRcPtr * /*et*/)
{ {
} }
void FallbackImpl::displayTransformSetLinearCC(OCIO_DisplayTransformRcPtr * /*dt*/, OCIO_ConstTransformRcPtr * /*et*/) void FallbackImpl::displayTransformSetLinearCC(OCIO_DisplayTransformRcPtr * /*dt*/,
OCIO_ConstTransformRcPtr * /*et*/)
{ {
} }
void FallbackImpl::displayTransformSetLooksOverride(OCIO_DisplayTransformRcPtr * /*dt*/, const char * /*looks*/) void FallbackImpl::displayTransformSetLooksOverride(OCIO_DisplayTransformRcPtr * /*dt*/,
const char * /*looks*/)
{ {
} }
void FallbackImpl::displayTransformSetLooksOverrideEnabled(OCIO_DisplayTransformRcPtr * /*dt*/, bool /*enabled*/) void FallbackImpl::displayTransformSetLooksOverrideEnabled(OCIO_DisplayTransformRcPtr * /*dt*/,
bool /*enabled*/)
{ {
} }
@ -375,11 +407,14 @@ void FallbackImpl::displayTransformRelease(OCIO_DisplayTransformRcPtr * /*dt*/)
{ {
} }
OCIO_PackedImageDesc *FallbackImpl::createOCIO_PackedImageDesc(float *data, long width, long height, long numChannels, OCIO_PackedImageDesc *FallbackImpl::createOCIO_PackedImageDesc(
long chanStrideBytes, long xStrideBytes, long yStrideBytes) float *data,
long width, long height, long numChannels,
long chanStrideBytes, long xStrideBytes, long yStrideBytes)
{ {
OCIO_PackedImageDescription *desc = (OCIO_PackedImageDescription*)MEM_callocN(sizeof(OCIO_PackedImageDescription), "OCIO_PackedImageDescription"); OCIO_PackedImageDescription *desc =
(OCIO_PackedImageDescription*)MEM_callocN(sizeof(OCIO_PackedImageDescription),
"OCIO_PackedImageDescription");
desc->data = data; desc->data = data;
desc->width = width; desc->width = width;
desc->height = height; desc->height = height;
@ -387,7 +422,6 @@ OCIO_PackedImageDesc *FallbackImpl::createOCIO_PackedImageDesc(float *data, long
desc->chanStrideBytes = chanStrideBytes; desc->chanStrideBytes = chanStrideBytes;
desc->xStrideBytes = xStrideBytes; desc->xStrideBytes = xStrideBytes;
desc->yStrideBytes = yStrideBytes; desc->yStrideBytes = yStrideBytes;
return (OCIO_PackedImageDesc*)desc; return (OCIO_PackedImageDesc*)desc;
} }
@ -401,7 +435,8 @@ OCIO_ExponentTransformRcPtr *FallbackImpl::createExponentTransform(void)
return (OCIO_ExponentTransformRcPtr*)PROCESSOR_UNKNOWN; return (OCIO_ExponentTransformRcPtr*)PROCESSOR_UNKNOWN;
} }
void FallbackImpl::exponentTransformSetValue(OCIO_ExponentTransformRcPtr * /*et*/, const float * /*exponent*/) void FallbackImpl::exponentTransformSetValue(OCIO_ExponentTransformRcPtr * /*et*/,
const float * /*exponent*/)
{ {
} }
@ -414,7 +449,9 @@ OCIO_MatrixTransformRcPtr *FallbackImpl::createMatrixTransform(void)
return (OCIO_MatrixTransformRcPtr*)PROCESSOR_UNKNOWN; return (OCIO_MatrixTransformRcPtr*)PROCESSOR_UNKNOWN;
} }
void FallbackImpl::matrixTransformSetValue(OCIO_MatrixTransformRcPtr * /*mt*/, const float * /*m44*/, const float * /*offset4*/) void FallbackImpl::matrixTransformSetValue(OCIO_MatrixTransformRcPtr * /*mt*/,
const float * /*m44*/,
const float * /*offset4*/)
{ {
} }
@ -422,7 +459,9 @@ void FallbackImpl::matrixTransformRelease(OCIO_MatrixTransformRcPtr * /*mt*/)
{ {
} }
void FallbackImpl::matrixTransformScale(float * /*m44*/, float * /*offset44*/, const float * /*scale4*/) void FallbackImpl::matrixTransformScale(float * /*m44*/,
float * /*offset44*/,
const float * /*scale4*/)
{ {
} }
@ -431,9 +470,11 @@ bool FallbackImpl::supportGLSLDraw(void)
return false; return false;
} }
bool FallbackImpl::setupGLSLDraw(struct OCIO_GLSLDrawState ** /*state_r*/, OCIO_ConstProcessorRcPtr * /*processor*/, bool FallbackImpl::setupGLSLDraw(struct OCIO_GLSLDrawState ** /*state_r*/,
OCIO_ConstProcessorRcPtr * /*processor*/,
OCIO_CurveMappingSettings * /*curve_mapping_settings*/, OCIO_CurveMappingSettings * /*curve_mapping_settings*/,
float /*dither*/, bool /*predivide*/) float /*dither*/,
bool /*predivide*/)
{ {
return false; return false;
} }

@ -32,25 +32,24 @@ from bpy_extras import object_utils
def add_torus(major_rad, minor_rad, major_seg, minor_seg): def add_torus(major_rad, minor_rad, major_seg, minor_seg):
from math import cos, sin, pi from math import cos, sin, pi
from mathutils import Vector, Quaternion from mathutils import Vector, Matrix
PI_2 = pi * 2.0 pi_2 = pi * 2.0
z_axis = 0.0, 0.0, 1.0
verts = [] verts = []
faces = [] faces = []
i1 = 0 i1 = 0
tot_verts = major_seg * minor_seg tot_verts = major_seg * minor_seg
for major_index in range(major_seg): for major_index in range(major_seg):
quat = Quaternion(z_axis, (major_index / major_seg) * PI_2) matrix = Matrix.Rotation((major_index / major_seg) * pi_2, 3, 'Z')
for minor_index in range(minor_seg): for minor_index in range(minor_seg):
angle = 2 * pi * minor_index / minor_seg angle = pi_2 * minor_index / minor_seg
vec = quat * Vector((major_rad + (cos(angle) * minor_rad), vec = matrix * Vector((major_rad + (cos(angle) * minor_rad),
0.0, 0.0,
(sin(angle) * minor_rad), sin(angle) * minor_rad,
)) ))
verts.extend(vec[:]) verts.extend(vec[:])
@ -58,7 +57,6 @@ def add_torus(major_rad, minor_rad, major_seg, minor_seg):
i2 = (major_index) * minor_seg i2 = (major_index) * minor_seg
i3 = i1 + minor_seg i3 = i1 + minor_seg
i4 = i2 + minor_seg i4 = i2 + minor_seg
else: else:
i2 = i1 + 1 i2 = i1 + 1
i3 = i1 + minor_seg i3 = i1 + minor_seg
@ -71,11 +69,7 @@ def add_torus(major_rad, minor_rad, major_seg, minor_seg):
if i4 >= tot_verts: if i4 >= tot_verts:
i4 = i4 - tot_verts i4 = i4 - tot_verts
# stupid eekadoodle faces.extend([i1, i3, i4, i2])
if i2:
faces.extend([i1, i3, i4, i2])
else:
faces.extend([i2, i1, i3, i4])
i1 += 1 i1 += 1
@ -83,31 +77,56 @@ def add_torus(major_rad, minor_rad, major_seg, minor_seg):
def add_uvs(mesh, minor_seg, major_seg): def add_uvs(mesh, minor_seg, major_seg):
from math import fmod
mesh.uv_textures.new() mesh.uv_textures.new()
uv_data = mesh.uv_layers.active.data uv_data = mesh.uv_layers.active.data
polygons = mesh.polygons polygons = mesh.polygons
u_step = 1.0 / major_seg u_step = 1.0 / major_seg
v_step = 1.0 / minor_seg v_step = 1.0 / minor_seg
# Round UV's, needed when segments aren't divisible by 4.
u_init = 0.5 + fmod(0.5, u_step)
v_init = 0.5 + fmod(0.5, v_step)
# Calculate wrapping value under 1.0 to prevent
# float precision errors wrapping at the wrong step.
u_wrap = 1.0 - (u_step / 2.0)
v_wrap = 1.0 - (v_step / 2.0)
vertex_index = 0 vertex_index = 0
u = 0.5 u_prev = u_init
u_next = u_prev + u_step
for major_index in range(major_seg): for major_index in range(major_seg):
v = 0.5 v_prev = v_init
v_next = v_prev + v_step
for minor_index in range(minor_seg): for minor_index in range(minor_seg):
loops = polygons[vertex_index].loop_indices loops = polygons[vertex_index].loop_indices
if minor_index == minor_seg - 1 and major_index == 0: if minor_index == minor_seg - 1 and major_index == 0:
uv_data[loops[1]].uv = (u, v) uv_data[loops[1]].uv = u_prev, v_prev
uv_data[loops[2]].uv = (u + u_step, v) uv_data[loops[2]].uv = u_next, v_prev
uv_data[loops[0]].uv = (u, v + v_step) uv_data[loops[0]].uv = u_prev, v_next
uv_data[loops[3]].uv = (u + u_step, v + v_step) uv_data[loops[3]].uv = u_next, v_next
else: else:
uv_data[loops[0]].uv = (u, v) uv_data[loops[0]].uv = u_prev, v_prev
uv_data[loops[1]].uv = (u + u_step, v) uv_data[loops[1]].uv = u_next, v_prev
uv_data[loops[3]].uv = (u, v + v_step) uv_data[loops[3]].uv = u_prev, v_next
uv_data[loops[2]].uv = (u + u_step, v + v_step) uv_data[loops[2]].uv = u_next, v_next
v = (v + v_step) % 1.0
if v_next > v_wrap:
v_prev = v_next - 1.0
else:
v_prev = v_next
v_next = v_prev + v_step
vertex_index += 1 vertex_index += 1
u = (u + u_step) % 1.0
if u_next > u_wrap:
u_prev = u_next - 1.0
else:
u_prev = u_next
u_next = u_prev + u_step
class AddTorus(Operator, object_utils.AddObjectHelper): class AddTorus(Operator, object_utils.AddObjectHelper):

@ -428,6 +428,12 @@ class USERPREF_PT_system(Panel):
col.separator() col.separator()
if bpy.app.build_options.cycles:
addon = userpref.addons.get("cycles")
if addon is not None:
addon.preferences.draw_impl(col, context)
del addon
if hasattr(system, "opensubdiv_compute_type"): if hasattr(system, "opensubdiv_compute_type"):
col.label(text="OpenSubdiv compute:") col.label(text="OpenSubdiv compute:")
col.row().prop(system, "opensubdiv_compute_type", text="") col.row().prop(system, "opensubdiv_compute_type", text="")

@ -138,11 +138,11 @@ void AbcCameraReader::readObjectData(Main *bmain, float time)
bcam->stereo.convergence_distance = convergence_plane.getValue(sample_sel); bcam->stereo.convergence_distance = convergence_plane.getValue(sample_sel);
} }
const float lens = cam_sample.getFocalLength(); const float lens = static_cast<float>(cam_sample.getFocalLength());
const float apperture_x = cam_sample.getHorizontalAperture(); const float apperture_x = static_cast<float>(cam_sample.getHorizontalAperture());
const float apperture_y = cam_sample.getVerticalAperture(); const float apperture_y = static_cast<float>(cam_sample.getVerticalAperture());
const float h_film_offset = cam_sample.getHorizontalFilmOffset(); const float h_film_offset = static_cast<float>(cam_sample.getHorizontalFilmOffset());
const float v_film_offset = cam_sample.getVerticalFilmOffset(); const float v_film_offset = static_cast<float>(cam_sample.getVerticalFilmOffset());
const float film_aspect = apperture_x / apperture_y; const float film_aspect = apperture_x / apperture_y;
bcam->lens = lens; bcam->lens = lens;
@ -150,10 +150,10 @@ void AbcCameraReader::readObjectData(Main *bmain, float time)
bcam->sensor_y = apperture_y * 10; bcam->sensor_y = apperture_y * 10;
bcam->shiftx = h_film_offset / apperture_x; bcam->shiftx = h_film_offset / apperture_x;
bcam->shifty = v_film_offset / apperture_y / film_aspect; bcam->shifty = v_film_offset / apperture_y / film_aspect;
bcam->clipsta = max_ff(0.1f, cam_sample.getNearClippingPlane()); bcam->clipsta = max_ff(0.1f, static_cast<float>(cam_sample.getNearClippingPlane()));
bcam->clipend = cam_sample.getFarClippingPlane(); bcam->clipend = static_cast<float>(cam_sample.getFarClippingPlane());
bcam->gpu_dof.focus_distance = cam_sample.getFocusDistance(); bcam->gpu_dof.focus_distance = static_cast<float>(cam_sample.getFocusDistance());
bcam->gpu_dof.fstop = cam_sample.getFStop(); bcam->gpu_dof.fstop = static_cast<float>(cam_sample.getFStop());
m_object = BKE_object_add_only_object(bmain, OB_CAMERA, m_object_name.c_str()); m_object = BKE_object_add_only_object(bmain, OB_CAMERA, m_object_name.c_str());
m_object->data = bcam; m_object->data = bcam;

@ -361,7 +361,7 @@ void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time)
* object directly and create a new DerivedMesh from that. Also we might need to * object directly and create a new DerivedMesh from that. Also we might need to
* create new or delete existing NURBS in the curve. * create new or delete existing NURBS in the curve.
*/ */
DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh */*dm*/, const float time, int /*read_flag*/) DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh */*dm*/, const float time, int /*read_flag*/, const char **/*err_str*/)
{ {
ISampleSelector sample_sel(time); ISampleSelector sample_sel(time);
const ICurvesSchema::Sample sample = m_curves_schema.getValue(sample_sel); const ICurvesSchema::Sample sample = m_curves_schema.getValue(sample_sel);

@ -56,7 +56,7 @@ public:
bool valid() const; bool valid() const;
void readObjectData(Main *bmain, float time); void readObjectData(Main *bmain, float time);
DerivedMesh *read_derivedmesh(DerivedMesh *, const float time, int); DerivedMesh *read_derivedmesh(DerivedMesh *, const float time, int read_flag, const char **err_str);
}; };
/* ************************************************************************** */ /* ************************************************************************** */

@ -26,6 +26,7 @@
#define __ABC_CUSTOMDATA_H__ #define __ABC_CUSTOMDATA_H__
#include <Alembic/Abc/All.h> #include <Alembic/Abc/All.h>
#include <Alembic/AbcGeom/All.h>
struct CustomData; struct CustomData;
struct MLoop; struct MLoop;
@ -65,8 +66,8 @@ struct CDStreamConfig {
float weight; float weight;
float time; float time;
int index; Alembic::AbcGeom::index_t index;
int ceil_index; Alembic::AbcGeom::index_t ceil_index;
CDStreamConfig() CDStreamConfig()
: mloop(NULL) : mloop(NULL)

@ -175,13 +175,13 @@ void AbcExporter::getShutterSamples(double step, bool time_relative,
/* sample all frame */ /* sample all frame */
if (shutter_open == 0.0 && shutter_close == 1.0) { if (shutter_open == 0.0 && shutter_close == 1.0) {
for (double t = 0; t < 1.0; t += step) { for (double t = 0.0; t < 1.0; t += step) {
samples.push_back((t + m_settings.frame_start) / time_factor); samples.push_back((t + m_settings.frame_start) / time_factor);
} }
} }
else { else {
/* sample between shutter open & close */ /* sample between shutter open & close */
const int nsamples = std::max((1.0 / step) - 1.0, 1.0); const int nsamples = static_cast<int>(std::max((1.0 / step) - 1.0, 1.0));
const double time_inc = (shutter_close - shutter_open) / nsamples; const double time_inc = (shutter_close - shutter_open) / nsamples;
for (double t = shutter_open; t <= shutter_close; t += time_inc) { for (double t = shutter_open; t <= shutter_close; t += time_inc) {
@ -216,7 +216,7 @@ void AbcExporter::getFrameSet(double step, std::set<double> &frames)
getShutterSamples(step, false, shutter_samples); getShutterSamples(step, false, shutter_samples);
for (int frame = m_settings.frame_start; frame <= m_settings.frame_end; ++frame) { for (double frame = m_settings.frame_start; frame <= m_settings.frame_end; frame += 1.0) {
for (int j = 0, e = shutter_samples.size(); j < e; ++j) { for (int j = 0, e = shutter_samples.size(); j < e; ++j) {
frames.insert(frame + shutter_samples[j]); frames.insert(frame + shutter_samples[j]);
} }
@ -237,9 +237,9 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled)
} }
Scene *scene = m_scene; Scene *scene = m_scene;
const int fps = FPS; const double fps = FPS;
char buf[16]; char buf[16];
snprintf(buf, 15, "%d", fps); snprintf(buf, 15, "%f", fps);
const std::string str_fps = buf; const std::string str_fps = buf;
Alembic::AbcCoreAbstract::MetaData md; Alembic::AbcCoreAbstract::MetaData md;
@ -561,7 +561,7 @@ AbcTransformWriter *AbcExporter::getXForm(const std::string &name)
void AbcExporter::setCurrentFrame(Main *bmain, double t) void AbcExporter::setCurrentFrame(Main *bmain, double t)
{ {
m_scene->r.cfra = std::floor(t); m_scene->r.cfra = static_cast<int>(t);
m_scene->r.subframe = t - m_scene->r.cfra; m_scene->r.subframe = static_cast<float>(t) - m_scene->r.cfra;
BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, m_scene, m_scene->lay); BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, m_scene, m_scene->lay);
} }

@ -868,53 +868,6 @@ ABC_INLINE void read_normals_params(AbcMeshData &abc_data,
} }
} }
/* ************************************************************************** */
AbcMeshReader::AbcMeshReader(const IObject &object, ImportSettings &settings)
: AbcObjectReader(object, settings)
{
m_settings->read_flag |= MOD_MESHSEQ_READ_ALL;
IPolyMesh ipoly_mesh(m_iobject, kWrapExisting);
m_schema = ipoly_mesh.getSchema();
get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time);
}
bool AbcMeshReader::valid() const
{
return m_schema.valid();
}
void AbcMeshReader::readObjectData(Main *bmain, float time)
{
Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
m_object->data = mesh;
const ISampleSelector sample_sel(time);
DerivedMesh *dm = CDDM_from_mesh(mesh);
DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL);
if (ndm != dm) {
dm->release(dm);
}
DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true);
if (m_settings->validate_meshes) {
BKE_mesh_validate(mesh, false, false);
}
readFaceSetsSample(bmain, mesh, 0, sample_sel);
if (has_animations(m_schema, m_settings)) {
addCacheModifier();
}
}
static bool check_smooth_poly_flag(DerivedMesh *dm) static bool check_smooth_poly_flag(DerivedMesh *dm)
{ {
MPoly *mpolys = dm->getPolyArray(dm); MPoly *mpolys = dm->getPolyArray(dm);
@ -962,6 +915,66 @@ static void *add_customdata_cb(void *user_data, const char *name, int data_type)
return cd_ptr; return cd_ptr;
} }
static void get_weight_and_index(CDStreamConfig &config,
Alembic::AbcCoreAbstract::TimeSamplingPtr time_sampling,
size_t samples_number)
{
Alembic::AbcGeom::index_t i0, i1;
config.weight = get_weight_and_index(config.time,
time_sampling,
samples_number,
i0,
i1);
config.index = i0;
config.ceil_index = i1;
}
static void read_mesh_sample(ImportSettings *settings,
const IPolyMeshSchema &schema,
const ISampleSelector &selector,
CDStreamConfig &config,
bool &do_normals)
{
const IPolyMeshSchema::Sample sample = schema.getValue(selector);
AbcMeshData abc_mesh_data;
abc_mesh_data.face_counts = sample.getFaceCounts();
abc_mesh_data.face_indices = sample.getFaceIndices();
abc_mesh_data.positions = sample.getPositions();
read_normals_params(abc_mesh_data, schema.getNormalsParam(), selector);
do_normals = (abc_mesh_data.face_normals != NULL);
get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples());
if (config.weight != 0.0f) {
Alembic::AbcGeom::IPolyMeshSchema::Sample ceil_sample;
schema.get(ceil_sample, Alembic::Abc::ISampleSelector(config.ceil_index));
abc_mesh_data.ceil_positions = ceil_sample.getPositions();
}
if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) {
read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector);
}
if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) {
read_mverts(config, abc_mesh_data);
}
if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
read_mpolys(config, abc_mesh_data);
}
if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
read_custom_data(schema.getArbGeomParams(), config, selector);
}
/* TODO: face sets */
}
CDStreamConfig get_config(DerivedMesh *dm) CDStreamConfig get_config(DerivedMesh *dm)
{ {
CDStreamConfig config; CDStreamConfig config;
@ -978,7 +991,54 @@ CDStreamConfig get_config(DerivedMesh *dm)
return config; return config;
} }
DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag) /* ************************************************************************** */
AbcMeshReader::AbcMeshReader(const IObject &object, ImportSettings &settings)
: AbcObjectReader(object, settings)
{
m_settings->read_flag |= MOD_MESHSEQ_READ_ALL;
IPolyMesh ipoly_mesh(m_iobject, kWrapExisting);
m_schema = ipoly_mesh.getSchema();
get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time);
}
bool AbcMeshReader::valid() const
{
return m_schema.valid();
}
void AbcMeshReader::readObjectData(Main *bmain, float time)
{
Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
m_object->data = mesh;
const ISampleSelector sample_sel(time);
DerivedMesh *dm = CDDM_from_mesh(mesh);
DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL, NULL);
if (ndm != dm) {
dm->release(dm);
}
DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true);
if (m_settings->validate_meshes) {
BKE_mesh_validate(mesh, false, false);
}
readFaceSetsSample(bmain, mesh, 0, sample_sel);
if (has_animations(m_schema, m_settings)) {
addCacheModifier();
}
}
DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str)
{ {
ISampleSelector sample_sel(time); ISampleSelector sample_sel(time);
const IPolyMeshSchema::Sample sample = m_schema.getValue(sample_sel); const IPolyMeshSchema::Sample sample = m_schema.getValue(sample_sel);
@ -1003,6 +1063,21 @@ DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, const float time,
settings.read_flag |= MOD_MESHSEQ_READ_ALL; settings.read_flag |= MOD_MESHSEQ_READ_ALL;
} }
else {
/* If the face count changed (e.g. by triangulation), only read points.
* This prevents crash from T49813.
* TODO(kevin): perhaps find a better way to do this? */
if (face_counts->size() != dm->getNumPolys(dm) ||
face_indices->size() != dm->getNumLoops(dm))
{
settings.read_flag = MOD_MESHSEQ_READ_VERT;
if (err_str) {
*err_str = "Topology has changed, perhaps by triangulating the"
" mesh. Only vertices will be read!";
}
}
}
CDStreamConfig config = get_config(new_dm ? new_dm : dm); CDStreamConfig config = get_config(new_dm ? new_dm : dm);
config.time = time; config.time = time;
@ -1078,44 +1153,40 @@ void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_star
utils::assign_materials(bmain, m_object, mat_map); utils::assign_materials(bmain, m_object, mat_map);
} }
static void get_weight_and_index(CDStreamConfig &config, /* ************************************************************************** */
Alembic::AbcCoreAbstract::TimeSamplingPtr time_sampling,
size_t samples_number) ABC_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2)
{ {
Alembic::AbcGeom::index_t i0, i1; for (int i = 0, e = totedge; i < e; ++i) {
MEdge &edge = edges[i];
config.weight = get_weight_and_index(config.time, if (edge.v1 == v1 && edge.v2 == v2) {
time_sampling, return &edge;
samples_number, }
i0, }
i1);
config.index = i0; return NULL;
config.ceil_index = i1;
} }
void read_mesh_sample(ImportSettings *settings, static void read_subd_sample(ImportSettings *settings,
const IPolyMeshSchema &schema, const ISubDSchema &schema,
const ISampleSelector &selector, const ISampleSelector &selector,
CDStreamConfig &config, CDStreamConfig &config)
bool &do_normals)
{ {
const IPolyMeshSchema::Sample sample = schema.getValue(selector); const ISubDSchema::Sample sample = schema.getValue(selector);
AbcMeshData abc_mesh_data; AbcMeshData abc_mesh_data;
abc_mesh_data.face_counts = sample.getFaceCounts(); abc_mesh_data.face_counts = sample.getFaceCounts();
abc_mesh_data.face_indices = sample.getFaceIndices(); abc_mesh_data.face_indices = sample.getFaceIndices();
abc_mesh_data.vertex_normals = N3fArraySamplePtr();
abc_mesh_data.face_normals = N3fArraySamplePtr();
abc_mesh_data.positions = sample.getPositions(); abc_mesh_data.positions = sample.getPositions();
read_normals_params(abc_mesh_data, schema.getNormalsParam(), selector);
do_normals = (abc_mesh_data.face_normals != NULL);
get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples()); get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples());
if (config.weight != 0.0f) { if (config.weight != 0.0f) {
Alembic::AbcGeom::IPolyMeshSchema::Sample ceil_sample; Alembic::AbcGeom::ISubDSchema::Sample ceil_sample;
schema.get(ceil_sample, Alembic::Abc::ISampleSelector(static_cast<Alembic::AbcCoreAbstract::index_t>(config.ceil_index))); schema.get(ceil_sample, Alembic::Abc::ISampleSelector(config.ceil_index));
abc_mesh_data.ceil_positions = ceil_sample.getPositions(); abc_mesh_data.ceil_positions = ceil_sample.getPositions();
} }
@ -1140,19 +1211,6 @@ void read_mesh_sample(ImportSettings *settings,
/* ************************************************************************** */ /* ************************************************************************** */
ABC_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2)
{
for (int i = 0, e = totedge; i < e; ++i) {
MEdge &edge = edges[i];
if (edge.v1 == v1 && edge.v2 == v2) {
return &edge;
}
}
return NULL;
}
AbcSubDReader::AbcSubDReader(const IObject &object, ImportSettings &settings) AbcSubDReader::AbcSubDReader(const IObject &object, ImportSettings &settings)
: AbcObjectReader(object, settings) : AbcObjectReader(object, settings)
{ {
@ -1177,7 +1235,7 @@ void AbcSubDReader::readObjectData(Main *bmain, float time)
m_object->data = mesh; m_object->data = mesh;
DerivedMesh *dm = CDDM_from_mesh(mesh); DerivedMesh *dm = CDDM_from_mesh(mesh);
DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL); DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL, NULL);
if (ndm != dm) { if (ndm != dm) {
dm->release(dm); dm->release(dm);
@ -1216,48 +1274,7 @@ void AbcSubDReader::readObjectData(Main *bmain, float time)
} }
} }
void read_subd_sample(ImportSettings *settings, DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str)
const ISubDSchema &schema,
const ISampleSelector &selector,
CDStreamConfig &config)
{
const ISubDSchema::Sample sample = schema.getValue(selector);
AbcMeshData abc_mesh_data;
abc_mesh_data.face_counts = sample.getFaceCounts();
abc_mesh_data.face_indices = sample.getFaceIndices();
abc_mesh_data.vertex_normals = N3fArraySamplePtr();
abc_mesh_data.face_normals = N3fArraySamplePtr();
abc_mesh_data.positions = sample.getPositions();
get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples());
if (config.weight != 0.0f) {
Alembic::AbcGeom::ISubDSchema::Sample ceil_sample;
schema.get(ceil_sample, Alembic::Abc::ISampleSelector(static_cast<Alembic::AbcCoreAbstract::index_t>(config.ceil_index)));
abc_mesh_data.ceil_positions = ceil_sample.getPositions();
}
if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) {
read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector);
}
if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) {
read_mverts(config, abc_mesh_data);
}
if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
read_mpolys(config, abc_mesh_data);
}
if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
read_custom_data(schema.getArbGeomParams(), config, selector);
}
/* TODO: face sets */
}
DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag)
{ {
ISampleSelector sample_sel(time); ISampleSelector sample_sel(time);
const ISubDSchema::Sample sample = m_schema.getValue(sample_sel); const ISubDSchema::Sample sample = m_schema.getValue(sample_sel);
@ -1281,6 +1298,21 @@ DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, const float time,
settings.read_flag |= MOD_MESHSEQ_READ_ALL; settings.read_flag |= MOD_MESHSEQ_READ_ALL;
} }
else {
/* If the face count changed (e.g. by triangulation), only read points.
* This prevents crash from T49813.
* TODO(kevin): perhaps find a better way to do this? */
if (face_counts->size() != dm->getNumPolys(dm) ||
face_indices->size() != dm->getNumLoops(dm))
{
settings.read_flag = MOD_MESHSEQ_READ_VERT;
if (err_str) {
*err_str = "Topology has changed, perhaps by triangulating the"
" mesh. Only vertices will be read!";
}
}
}
/* Only read point data when streaming meshes, unless we need to create new ones. */ /* Only read point data when streaming meshes, unless we need to create new ones. */
CDStreamConfig config = get_config(new_dm ? new_dm : dm); CDStreamConfig config = get_config(new_dm ? new_dm : dm);

@ -102,19 +102,13 @@ public:
void readObjectData(Main *bmain, float time); void readObjectData(Main *bmain, float time);
DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag); DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str);
private: private:
void readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start, void readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start,
const Alembic::AbcGeom::ISampleSelector &sample_sel); const Alembic::AbcGeom::ISampleSelector &sample_sel);
}; };
void read_mesh_sample(ImportSettings *settings,
const Alembic::AbcGeom::IPolyMeshSchema &schema,
const Alembic::AbcGeom::ISampleSelector &selector,
CDStreamConfig &config,
bool &do_normals);
/* ************************************************************************** */ /* ************************************************************************** */
class AbcSubDReader : public AbcObjectReader { class AbcSubDReader : public AbcObjectReader {
@ -128,14 +122,9 @@ public:
bool valid() const; bool valid() const;
void readObjectData(Main *bmain, float time); void readObjectData(Main *bmain, float time);
DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag); DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str);
}; };
void read_subd_sample(ImportSettings *settings,
const Alembic::AbcGeom::ISubDSchema &schema,
const Alembic::AbcGeom::ISampleSelector &selector,
CDStreamConfig &config);
/* ************************************************************************** */ /* ************************************************************************** */
void read_mverts(MVert *mverts, void read_mverts(MVert *mverts,

@ -170,13 +170,13 @@ static Imath::M44d blend_matrices(const Imath::M44d &m0, const Imath::M44d &m1,
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) { for (int j = 0; j < 4; ++j) {
mat0[i][j] = m0[i][j]; mat0[i][j] = static_cast<float>(m0[i][j]);
} }
} }
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) { for (int j = 0; j < 4; ++j) {
mat1[i][j] = m1[i][j]; mat1[i][j] = static_cast<float>(m1[i][j]);
} }
} }

@ -76,7 +76,7 @@ private:
/* ************************************************************************** */ /* ************************************************************************** */
class CacheFile; struct CacheFile;
struct ImportSettings { struct ImportSettings {
bool do_convert_mat; bool do_convert_mat;
@ -165,10 +165,11 @@ public:
virtual void readObjectData(Main *bmain, float time) = 0; virtual void readObjectData(Main *bmain, float time) = 0;
virtual DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag) virtual DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str)
{ {
(void)time; (void)time;
(void)read_flag; (void)read_flag;
(void)err_str;
return dm; return dm;
} }

@ -158,7 +158,7 @@ void AbcPointsReader::readObjectData(Main *bmain, float time)
Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str()); Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
DerivedMesh *dm = CDDM_from_mesh(mesh); DerivedMesh *dm = CDDM_from_mesh(mesh);
DerivedMesh *ndm = this->read_derivedmesh(dm, time, 0); DerivedMesh *ndm = this->read_derivedmesh(dm, time, 0, NULL);
if (ndm != dm) { if (ndm != dm) {
dm->release(dm); dm->release(dm);
@ -191,7 +191,8 @@ void read_points_sample(const IPointsSchema &schema,
N3fArraySamplePtr vnormals; N3fArraySamplePtr vnormals;
if (has_property(prop, "N")) { if (has_property(prop, "N")) {
const IN3fArrayProperty &normals_prop = IN3fArrayProperty(prop, "N", time); const Alembic::Util::uint32_t itime = static_cast<Alembic::Util::uint32_t>(time);
const IN3fArrayProperty &normals_prop = IN3fArrayProperty(prop, "N", itime);
if (normals_prop) { if (normals_prop) {
vnormals = normals_prop.getValue(selector); vnormals = normals_prop.getValue(selector);
@ -201,7 +202,7 @@ void read_points_sample(const IPointsSchema &schema,
read_mverts(config.mvert, positions, vnormals); read_mverts(config.mvert, positions, vnormals);
} }
DerivedMesh *AbcPointsReader::read_derivedmesh(DerivedMesh *dm, const float time, int /*read_flag*/) DerivedMesh *AbcPointsReader::read_derivedmesh(DerivedMesh *dm, const float time, int /*read_flag*/, const char **/*err_str*/)
{ {
ISampleSelector sample_sel(time); ISampleSelector sample_sel(time);
const IPointsSchema::Sample sample = m_schema.getValue(sample_sel); const IPointsSchema::Sample sample = m_schema.getValue(sample_sel);

@ -59,7 +59,7 @@ public:
void readObjectData(Main *bmain, float time); void readObjectData(Main *bmain, float time);
DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag); DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str);
}; };
void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema, void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema,

@ -92,8 +92,7 @@ void AbcTransformWriter::do_write()
/* Only apply rotation to root camera, parenting will propagate it. */ /* Only apply rotation to root camera, parenting will propagate it. */
if (m_object->type == OB_CAMERA && !has_parent_camera(m_object)) { if (m_object->type == OB_CAMERA && !has_parent_camera(m_object)) {
float rot_mat[4][4]; float rot_mat[4][4];
unit_m4(rot_mat); axis_angle_to_mat4_single(rot_mat, 'X', -M_PI_2);
rotate_m4(rot_mat, 'X', -M_PI_2);
mul_m4_m4m4(mat, mat, rot_mat); mul_m4_m4m4(mat, mat, rot_mat);
} }

@ -215,14 +215,13 @@ void convert_matrix(const Imath::M44d &xform, Object *ob,
{ {
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) { for (int j = 0; j < 4; ++j) {
r_mat[i][j] = xform[i][j]; r_mat[i][j] = static_cast<float>(xform[i][j]);
} }
} }
if (ob->type == OB_CAMERA) { if (ob->type == OB_CAMERA) {
float cam_to_yup[4][4]; float cam_to_yup[4][4];
unit_m4(cam_to_yup); axis_angle_to_mat4_single(cam_to_yup, 'X', M_PI_2);
rotate_m4(cam_to_yup, 'X', M_PI_2);
mul_m4_m4m4(r_mat, r_mat, cam_to_yup); mul_m4_m4m4(r_mat, r_mat, cam_to_yup);
} }

@ -39,7 +39,7 @@ struct CacheReader {
using Alembic::Abc::chrono_t; using Alembic::Abc::chrono_t;
class AbcObjectReader; class AbcObjectReader;
class ImportSettings; struct ImportSettings;
struct ID; struct ID;
struct Object; struct Object;

@ -625,8 +625,8 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
CFRA = SFRA; CFRA = SFRA;
} }
else if (min_time < max_time) { else if (min_time < max_time) {
SFRA = min_time * FPS; SFRA = static_cast<int>(min_time * FPS);
EFRA = max_time * FPS; EFRA = static_cast<int>(max_time * FPS);
CFRA = SFRA; CFRA = SFRA;
} }
} }
@ -816,7 +816,7 @@ DerivedMesh *ABC_read_mesh(CacheReader *reader,
return NULL; return NULL;
} }
return abc_reader->read_derivedmesh(dm, time, read_flag); return abc_reader->read_derivedmesh(dm, time, read_flag, err_str);
} }
else if (ISubD::matches(header)) { else if (ISubD::matches(header)) {
if (ob->type != OB_MESH) { if (ob->type != OB_MESH) {
@ -824,7 +824,7 @@ DerivedMesh *ABC_read_mesh(CacheReader *reader,
return NULL; return NULL;
} }
return abc_reader->read_derivedmesh(dm, time, read_flag); return abc_reader->read_derivedmesh(dm, time, read_flag, err_str);
} }
else if (IPoints::matches(header)) { else if (IPoints::matches(header)) {
if (ob->type != OB_MESH) { if (ob->type != OB_MESH) {
@ -832,7 +832,7 @@ DerivedMesh *ABC_read_mesh(CacheReader *reader,
return NULL; return NULL;
} }
return abc_reader->read_derivedmesh(dm, time, read_flag); return abc_reader->read_derivedmesh(dm, time, read_flag, err_str);
} }
else if (ICurves::matches(header)) { else if (ICurves::matches(header)) {
if (ob->type != OB_CURVE) { if (ob->type != OB_CURVE) {
@ -840,7 +840,7 @@ DerivedMesh *ABC_read_mesh(CacheReader *reader,
return NULL; return NULL;
} }
return abc_reader->read_derivedmesh(dm, time, read_flag); return abc_reader->read_derivedmesh(dm, time, read_flag, err_str);
} }
*err_str = "Unsupported object type: verify object path"; // or poke developer *err_str = "Unsupported object type: verify object path"; // or poke developer

@ -73,7 +73,7 @@ struct AnimData *BKE_animdata_copy(struct AnimData *adt, const bool do_action);
bool BKE_animdata_copy_id(struct ID *id_to, struct ID *id_from, const bool do_action); bool BKE_animdata_copy_id(struct ID *id_to, struct ID *id_from, const bool do_action);
/* Copy AnimData Actions */ /* Copy AnimData Actions */
void BKE_animdata_copy_id_action(struct ID *id); void BKE_animdata_copy_id_action(struct ID *id, const bool set_newid);
/* Merge copies of data from source AnimData block */ /* Merge copies of data from source AnimData block */
typedef enum eAnimData_MergeCopy_Modes { typedef enum eAnimData_MergeCopy_Modes {

@ -120,7 +120,6 @@ void BKE_constraint_unique_name(struct bConstraint *con, struct ListBase *list);
void BKE_constraints_free(struct ListBase *list); void BKE_constraints_free(struct ListBase *list);
void BKE_constraints_free_ex(struct ListBase *list, bool do_id_user); void BKE_constraints_free_ex(struct ListBase *list, bool do_id_user);
void BKE_constraints_copy(struct ListBase *dst, const struct ListBase *src, bool do_extern); void BKE_constraints_copy(struct ListBase *dst, const struct ListBase *src, bool do_extern);
void BKE_constraints_relink(struct ListBase *list);
void BKE_constraints_id_loop(struct ListBase *list, ConstraintIDFunc func, void *userdata); void BKE_constraints_id_loop(struct ListBase *list, ConstraintIDFunc func, void *userdata);
void BKE_constraint_free_data(struct bConstraint *con); void BKE_constraint_free_data(struct bConstraint *con);
void BKE_constraint_free_data_ex(struct bConstraint *con, bool do_id_user); void BKE_constraint_free_data_ex(struct bConstraint *con, bool do_id_user);

@ -80,6 +80,7 @@ void id_us_plus(struct ID *id);
void id_us_min(struct ID *id); void id_us_min(struct ID *id);
void id_fake_user_set(struct ID *id); void id_fake_user_set(struct ID *id);
void id_fake_user_clear(struct ID *id); void id_fake_user_clear(struct ID *id);
void BKE_id_clear_newpoin(struct ID *id);
void BKE_id_make_local_generic(struct Main *bmain, struct ID *id, const bool id_in_mainlist, const bool lib_local); void BKE_id_make_local_generic(struct Main *bmain, struct ID *id, const bool id_in_mainlist, const bool lib_local);
bool id_make_local(struct Main *bmain, struct ID *id, const bool test, const bool force_local); bool id_make_local(struct Main *bmain, struct ID *id, const bool test, const bool force_local);

@ -307,17 +307,19 @@ bool BKE_animdata_copy_id(ID *id_to, ID *id_from, const bool do_action)
return true; return true;
} }
void BKE_animdata_copy_id_action(ID *id) void BKE_animdata_copy_id_action(ID *id, const bool set_newid)
{ {
AnimData *adt = BKE_animdata_from_id(id); AnimData *adt = BKE_animdata_from_id(id);
if (adt) { if (adt) {
if (adt->action) { if (adt->action) {
id_us_min((ID *)adt->action); id_us_min((ID *)adt->action);
adt->action = BKE_action_copy(G.main, adt->action); adt->action = set_newid ? ID_NEW_SET(adt->action, BKE_action_copy(G.main, adt->action)) :
BKE_action_copy(G.main, adt->action);
} }
if (adt->tmpact) { if (adt->tmpact) {
id_us_min((ID *)adt->tmpact); id_us_min((ID *)adt->tmpact);
adt->tmpact = BKE_action_copy(G.main, adt->tmpact); adt->tmpact = set_newid ? ID_NEW_SET(adt->tmpact, BKE_action_copy(G.main, adt->tmpact)) :
BKE_action_copy(G.main, adt->tmpact);
} }
} }
} }

@ -249,6 +249,9 @@ void BKE_brush_make_local(Main *bmain, Brush *brush, const bool lib_local)
brush_new->id.us = 0; brush_new->id.us = 0;
/* setting newid is mandatory for complex make_lib_local logic... */
ID_NEW_SET(brush, brush_new);
if (!lib_local) { if (!lib_local) {
BKE_libblock_remap(bmain, brush, brush_new, ID_REMAP_SKIP_INDIRECT_USAGE); BKE_libblock_remap(bmain, brush, brush_new, ID_REMAP_SKIP_INDIRECT_USAGE);
} }

@ -252,7 +252,7 @@ void BKE_camera_params_from_view3d(CameraParams *params, const View3D *v3d, cons
} }
else if (rv3d->persp == RV3D_ORTHO) { else if (rv3d->persp == RV3D_ORTHO) {
/* orthographic view */ /* orthographic view */
int sensor_size = BKE_camera_sensor_size(params->sensor_fit, params->sensor_x, params->sensor_y); float sensor_size = BKE_camera_sensor_size(params->sensor_fit, params->sensor_x, params->sensor_y);
params->clipend *= 0.5f; // otherwise too extreme low zbuffer quality params->clipend *= 0.5f; // otherwise too extreme low zbuffer quality
params->clipsta = -params->clipend; params->clipsta = -params->clipend;
@ -337,6 +337,8 @@ void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int win
viewplane.ymin *= pixsize; viewplane.ymin *= pixsize;
viewplane.ymax *= pixsize; viewplane.ymax *= pixsize;
/* Used for rendering (offset by near-clip with perspective views), passed to RE_SetPixelSize.
* For viewport drawing 'RegionView3D.pixsize'. */
params->viewdx = pixsize; params->viewdx = pixsize;
params->viewdy = params->ycor * pixsize; params->viewdy = params->ycor * pixsize;
params->viewplane = viewplane; params->viewplane = viewplane;

@ -4705,27 +4705,6 @@ bConstraint *BKE_constraint_add_for_object(Object *ob, const char *name, short t
/* ......... */ /* ......... */
/* helper for BKE_constraints_relink() - call ID_NEW() on every ID reference the constraint has */
static void con_relink_id_cb(bConstraint *UNUSED(con), ID **idpoin, bool UNUSED(is_reference), void *UNUSED(userdata))
{
/* ID_NEW() expects a struct with inline "id" member as first
* since we've got the actual ID block, let's just inline this
* code.
*
* See ID_NEW(a) in DNA_ID.h
*/
if ((*idpoin) && (*idpoin)->newid)
(*idpoin) = (void *)(*idpoin)->newid;
}
/* Reassign links that constraints have to other data (called during file loading?) */
void BKE_constraints_relink(ListBase *conlist)
{
/* just a wrapper around ID-loop for just calling ID_NEW() on all ID refs */
BKE_constraints_id_loop(conlist, con_relink_id_cb, NULL);
}
/* Run the given callback on all ID-blocks in list of constraints */ /* Run the given callback on all ID-blocks in list of constraints */
void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *userdata) void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *userdata)
{ {

@ -1354,7 +1354,6 @@ static void scene_sort_groups(Main *bmain, Scene *sce)
/* test; are group objects all in this scene? */ /* test; are group objects all in this scene? */
for (ob = bmain->object.first; ob; ob = ob->id.next) { for (ob = bmain->object.first; ob; ob = ob->id.next) {
ob->id.tag &= ~LIB_TAG_DOIT; ob->id.tag &= ~LIB_TAG_DOIT;
ob->id.newid = NULL; /* newid abuse for GroupObject */
} }
for (base = sce->base.first; base; base = base->next) for (base = sce->base.first; base; base = base->next)
base->object->id.tag |= LIB_TAG_DOIT; base->object->id.tag |= LIB_TAG_DOIT;
@ -1385,6 +1384,11 @@ static void scene_sort_groups(Main *bmain, Scene *sce)
group->gobject = listb; group->gobject = listb;
} }
} }
/* newid abused for GroupObject, cleanup. */
for (ob = bmain->object.first; ob; ob = ob->id.next) {
ob->id.newid = NULL;
}
} }
static void dag_scene_tag_rebuild(Scene *sce) static void dag_scene_tag_rebuild(Scene *sce)

@ -382,7 +382,8 @@ bGPDpalette *BKE_gpencil_palette_addnew(bGPdata *gpd, const char *name, bool set
sizeof(palette->info)); sizeof(palette->info));
/* make this one the active one */ /* make this one the active one */
if (setactive) { /* NOTE: Always make this active if there's nothing else yet (T50123) */
if ((setactive) || (gpd->palettes.first == gpd->palettes.last)) {
BKE_gpencil_palette_setactive(gpd, palette); BKE_gpencil_palette_setactive(gpd, palette);
} }
@ -1264,6 +1265,10 @@ void BKE_gpencil_palettecolor_changename(bGPdata *gpd, char *oldname, const char
bGPDframe *gpf; bGPDframe *gpf;
bGPDstroke *gps; bGPDstroke *gps;
/* Sanity checks (gpd may not be set in the RNA pointers sometimes) */
if (ELEM(NULL, gpd, oldname, newname))
return;
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
for (gps = gpf->strokes.first; gps; gps = gps->next) { for (gps = gpf->strokes.first; gps; gps = gps->next) {
@ -1283,6 +1288,10 @@ void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name)
bGPDframe *gpf; bGPDframe *gpf;
bGPDstroke *gps, *gpsn; bGPDstroke *gps, *gpsn;
/* Sanity checks (gpd may not be set in the RNA pointers sometimes) */
if (ELEM(NULL, gpd, name))
return;
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
for (gps = gpf->strokes.first; gps; gps = gpsn) { for (gps = gpf->strokes.first; gps; gps = gpsn) {

@ -436,7 +436,6 @@ static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src)
Image *BKE_image_copy(Main *bmain, Image *ima) Image *BKE_image_copy(Main *bmain, Image *ima)
{ {
Image *nima = image_alloc(bmain, ima->id.name + 2, ima->source, ima->type); Image *nima = image_alloc(bmain, ima->id.name + 2, ima->source, ima->type);
ima->id.newid = &nima->id;
BLI_strncpy(nima->name, ima->name, sizeof(ima->name)); BLI_strncpy(nima->name, ima->name, sizeof(ima->name));

@ -262,6 +262,14 @@ void id_fake_user_clear(ID *id)
} }
} }
void BKE_id_clear_newpoin(ID *id)
{
if (id->newid) {
id->newid->tag &= ~LIB_TAG_NEW;
}
id->newid = NULL;
}
static int id_expand_local_callback( static int id_expand_local_callback(
void *UNUSED(user_data), struct ID *id_self, struct ID **id_pointer, int UNUSED(cd_flag)) void *UNUSED(user_data), struct ID *id_self, struct ID **id_pointer, int UNUSED(cd_flag))
{ {
@ -325,6 +333,17 @@ void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, c
if (id_copy(bmain, id, &id_new, false)) { if (id_copy(bmain, id, &id_new, false)) {
id_new->us = 0; id_new->us = 0;
/* setting newid is mandatory for complex make_lib_local logic... */
ID_NEW_SET(id, id_new);
Key *key = BKE_key_from_id(id), *key_new = BKE_key_from_id(id);
if (key && key_new) {
ID_NEW_SET(key, key_new);
}
bNodeTree *ntree = ntreeFromID(id), *ntree_new = ntreeFromID(id_new);
if (ntree && ntree_new) {
ID_NEW_SET(ntree, ntree_new);
}
if (!lib_local) { if (!lib_local) {
BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE); BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE);
} }
@ -336,6 +355,8 @@ void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, c
/** /**
* Calls the appropriate make_local method for the block, unless test is set. * Calls the appropriate make_local method for the block, unless test is set.
* *
* \note Always set ID->newid pointer in case it gets duplicated...
*
* \param lib_local Special flag used when making a whole library's content local, it needs specific handling. * \param lib_local Special flag used when making a whole library's content local, it needs specific handling.
* *
* \return true if the block can be made local. * \return true if the block can be made local.
@ -554,6 +575,7 @@ bool id_copy(Main *bmain, ID *id, ID **newid, bool test)
return false; return false;
} }
/** Does *not* set ID->newid pointer. */
bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop) bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
{ {
ID *newid = NULL; ID *newid = NULL;
@ -564,7 +586,7 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
if (RNA_property_editable(ptr, prop)) { if (RNA_property_editable(ptr, prop)) {
if (id_copy(CTX_data_main(C), id, &newid, false) && newid) { if (id_copy(CTX_data_main(C), id, &newid, false) && newid) {
/* copy animation actions too */ /* copy animation actions too */
BKE_animdata_copy_id_action(id); BKE_animdata_copy_id_action(id, false);
/* us is 1 by convention, but RNA_property_pointer_set /* us is 1 by convention, but RNA_property_pointer_set
* will also increment it, so set it to zero */ * will also increment it, so set it to zero */
newid->us = 0; newid->us = 0;
@ -1105,9 +1127,6 @@ void *BKE_libblock_copy(Main *bmain, ID *id)
memcpy(cpn + sizeof(ID), cp + sizeof(ID), idn_len - sizeof(ID)); memcpy(cpn + sizeof(ID), cp + sizeof(ID), idn_len - sizeof(ID));
} }
id->newid = idn;
idn->tag |= LIB_TAG_NEW;
BKE_libblock_copy_data(idn, id, false); BKE_libblock_copy_data(idn, id, false);
return idn; return idn;
@ -1131,8 +1150,6 @@ void *BKE_libblock_copy_nolib(ID *id, const bool do_action)
memcpy(cpn + sizeof(ID), cp + sizeof(ID), idn_len - sizeof(ID)); memcpy(cpn + sizeof(ID), cp + sizeof(ID), idn_len - sizeof(ID));
} }
id->newid = idn;
idn->tag |= LIB_TAG_NEW;
idn->us = 1; idn->us = 1;
BKE_libblock_copy_data(idn, id, do_action); BKE_libblock_copy_data(idn, id, do_action);
@ -1646,7 +1663,6 @@ void BKE_library_make_local(
const bool do_skip = (id && !BKE_idcode_is_linkable(GS(id->name))); const bool do_skip = (id && !BKE_idcode_is_linkable(GS(id->name)));
for (; id; id = id->next) { for (; id; id = id->next) {
id->newid = NULL;
id->tag &= ~LIB_TAG_DOIT; id->tag &= ~LIB_TAG_DOIT;
if (id->lib == NULL) { if (id->lib == NULL) {
@ -1846,6 +1862,7 @@ void BKE_library_make_local(
} }
} }
BKE_main_id_clear_newpoins(bmain);
BLI_memarena_free(linklist_mem); BLI_memarena_free(linklist_mem);
} }

@ -1052,6 +1052,9 @@ void BKE_object_make_local_ex(Main *bmain, Object *ob, const bool lib_local, con
ob_new->id.us = 0; ob_new->id.us = 0;
ob_new->proxy = ob_new->proxy_from = ob_new->proxy_group = NULL; ob_new->proxy = ob_new->proxy_from = ob_new->proxy_group = NULL;
/* setting newid is mandatory for complex make_lib_local logic... */
ID_NEW_SET(ob, ob_new);
if (!lib_local) { if (!lib_local) {
BKE_libblock_remap(bmain, ob, ob_new, ID_REMAP_SKIP_INDIRECT_USAGE); BKE_libblock_remap(bmain, ob, ob_new, ID_REMAP_SKIP_INDIRECT_USAGE);
} }
@ -1185,6 +1188,9 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
ob->data = target->data; ob->data = target->data;
id_us_plus((ID *)ob->data); /* ensures lib data becomes LIB_TAG_EXTERN */ id_us_plus((ID *)ob->data); /* ensures lib data becomes LIB_TAG_EXTERN */
/* copy vertex groups */
defgroup_copy_list(&ob->defbase, &target->defbase);
/* copy material and index information */ /* copy material and index information */
ob->actcol = ob->totcol = 0; ob->actcol = ob->totcol = 0;
if (ob->mat) MEM_freeN(ob->mat); if (ob->mat) MEM_freeN(ob->mat);

@ -642,8 +642,7 @@ static void make_duplis_font(const DupliContext *ctx)
float rmat[4][4]; float rmat[4][4];
zero_v3(obmat[3]); zero_v3(obmat[3]);
unit_m4(rmat); axis_angle_to_mat4_single(rmat, 'Z', -ct->rot);
rotate_m4(rmat, 'Z', -ct->rot);
mul_m4_m4m4(obmat, obmat, rmat); mul_m4_m4m4(obmat, obmat, rmat);
} }

@ -220,8 +220,8 @@ RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob)
/* preserve relationships between constraints and rigid bodies after duplication */ /* preserve relationships between constraints and rigid bodies after duplication */
void BKE_rigidbody_relink_constraint(RigidBodyCon *rbc) void BKE_rigidbody_relink_constraint(RigidBodyCon *rbc)
{ {
ID_NEW(rbc->ob1); ID_NEW_REMAP(rbc->ob1);
ID_NEW(rbc->ob2); ID_NEW_REMAP(rbc->ob2);
} }
/* ************************************** */ /* ************************************** */

@ -602,41 +602,41 @@ void set_sca_new_poins_ob(Object *ob)
if (act->flag & ACT_NEW) { if (act->flag & ACT_NEW) {
if (act->type==ACT_EDIT_OBJECT) { if (act->type==ACT_EDIT_OBJECT) {
bEditObjectActuator *eoa= act->data; bEditObjectActuator *eoa= act->data;
ID_NEW(eoa->ob); ID_NEW_REMAP(eoa->ob);
} }
else if (act->type==ACT_SCENE) { else if (act->type==ACT_SCENE) {
bSceneActuator *sca= act->data; bSceneActuator *sca= act->data;
ID_NEW(sca->camera); ID_NEW_REMAP(sca->camera);
} }
else if (act->type==ACT_CAMERA) { else if (act->type==ACT_CAMERA) {
bCameraActuator *ca= act->data; bCameraActuator *ca= act->data;
ID_NEW(ca->ob); ID_NEW_REMAP(ca->ob);
} }
else if (act->type==ACT_OBJECT) { else if (act->type==ACT_OBJECT) {
bObjectActuator *oa= act->data; bObjectActuator *oa= act->data;
ID_NEW(oa->reference); ID_NEW_REMAP(oa->reference);
} }
else if (act->type==ACT_MESSAGE) { else if (act->type==ACT_MESSAGE) {
bMessageActuator *ma= act->data; bMessageActuator *ma= act->data;
ID_NEW(ma->toObject); ID_NEW_REMAP(ma->toObject);
} }
else if (act->type==ACT_PARENT) { else if (act->type==ACT_PARENT) {
bParentActuator *para = act->data; bParentActuator *para = act->data;
ID_NEW(para->ob); ID_NEW_REMAP(para->ob);
} }
else if (act->type==ACT_ARMATURE) { else if (act->type==ACT_ARMATURE) {
bArmatureActuator *aa = act->data; bArmatureActuator *aa = act->data;
ID_NEW(aa->target); ID_NEW_REMAP(aa->target);
ID_NEW(aa->subtarget); ID_NEW_REMAP(aa->subtarget);
} }
else if (act->type==ACT_PROPERTY) { else if (act->type==ACT_PROPERTY) {
bPropertyActuator *pa= act->data; bPropertyActuator *pa= act->data;
ID_NEW(pa->ob); ID_NEW_REMAP(pa->ob);
} }
else if (act->type==ACT_STEERING) { else if (act->type==ACT_STEERING) {
bSteeringActuator *sta = act->data; bSteeringActuator *sta = act->data;
ID_NEW(sta->navmesh); ID_NEW_REMAP(sta->navmesh);
ID_NEW(sta->target); ID_NEW_REMAP(sta->target);
} }
} }
act= act->next; act= act->next;

@ -186,8 +186,6 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
scen = BKE_libblock_copy(bmain, &sce->id); scen = BKE_libblock_copy(bmain, &sce->id);
BLI_duplicatelist(&(scen->base), &(sce->base)); BLI_duplicatelist(&(scen->base), &(sce->base));
BKE_main_id_clear_newpoins(bmain);
id_us_plus((ID *)scen->world); id_us_plus((ID *)scen->world);
id_us_plus((ID *)scen->set); id_us_plus((ID *)scen->set);
/* id_us_plus((ID *)scen->gm.dome.warptext); */ /* XXX Not refcounted? see readfile.c */ /* id_us_plus((ID *)scen->gm.dome.warptext); */ /* XXX Not refcounted? see readfile.c */
@ -225,7 +223,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
} }
/* copy action and remove animation used by sequencer */ /* copy action and remove animation used by sequencer */
BKE_animdata_copy_id_action(&scen->id); BKE_animdata_copy_id_action(&scen->id, false);
if (type != SCE_COPY_FULL) if (type != SCE_COPY_FULL)
remove_sequencer_fcurves(scen); remove_sequencer_fcurves(scen);
@ -317,7 +315,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
/* camera */ /* camera */
if (type == SCE_COPY_LINK_DATA || type == SCE_COPY_FULL) { if (type == SCE_COPY_LINK_DATA || type == SCE_COPY_FULL) {
ID_NEW(scen->camera); ID_NEW_REMAP(scen->camera);
} }
/* before scene copy */ /* before scene copy */
@ -328,7 +326,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
if (scen->world) { if (scen->world) {
id_us_plus((ID *)scen->world); id_us_plus((ID *)scen->world);
scen->world = BKE_world_copy(bmain, scen->world); scen->world = BKE_world_copy(bmain, scen->world);
BKE_animdata_copy_id_action((ID *)scen->world); BKE_animdata_copy_id_action((ID *)scen->world, false);
} }
if (sce->ed) { if (sce->ed) {

@ -320,7 +320,8 @@ void BKE_sequencer_free_clipboard(void)
/* Manage pointers in the clipboard. /* Manage pointers in the clipboard.
* note that these pointers should _never_ be access in the sequencer, * note that these pointers should _never_ be access in the sequencer,
* they are only for storage while in the clipboard * they are only for storage while in the clipboard
* notice 'newid' is used for temp pointer storage here, validate on access. * notice 'newid' is used for temp pointer storage here, validate on access (this is safe usage,
* since those datablocks are fully out of Main lists).
*/ */
#define ID_PT (*id_pt) #define ID_PT (*id_pt)
static void seqclipboard_ptr_free(ID **id_pt) static void seqclipboard_ptr_free(ID **id_pt)

@ -587,7 +587,7 @@ static void compensate_rotation_center(const int size, float aspect,
copy_v2_v2(intended_pivot, pivot); copy_v2_v2(intended_pivot, pivot);
copy_v2_v2(rotated_pivot, pivot); copy_v2_v2(rotated_pivot, pivot);
rotate_m2(rotation_mat, +angle); angle_to_mat2(rotation_mat, +angle);
sub_v2_v2(rotated_pivot, origin); sub_v2_v2(rotated_pivot, origin);
mul_m2v2(rotation_mat, rotated_pivot); mul_m2v2(rotation_mat, rotated_pivot);
mul_v2_fl(rotated_pivot, scale); mul_v2_fl(rotated_pivot, scale);
@ -967,7 +967,7 @@ static void initialize_track_for_stabilization(StabContext *ctx,
pos[0] *= aspect; pos[0] *= aspect;
angle = average_angle - atan2f(pos[1],pos[0]); angle = average_angle - atan2f(pos[1],pos[0]);
rotate_m2(local_data->stabilization_rotation_base, angle); angle_to_mat2(local_data->stabilization_rotation_base, angle);
/* Per track baseline value for zoom. */ /* Per track baseline value for zoom. */
len = len_v2(pos) + SCALE_ERROR_LIMIT_BIAS; len = len_v2(pos) + SCALE_ERROR_LIMIT_BIAS;

@ -232,7 +232,6 @@ void mat4_to_size(float r[3], const float M[4][4]);
void translate_m4(float mat[4][4], float tx, float ty, float tz); void translate_m4(float mat[4][4], float tx, float ty, float tz);
void rotate_m4(float mat[4][4], const char axis, const float angle); void rotate_m4(float mat[4][4], const char axis, const float angle);
void rotate_m2(float mat[2][2], const float angle);
void transform_pivot_set_m4(float mat[4][4], const float pivot[3]); void transform_pivot_set_m4(float mat[4][4], const float pivot[3]);
void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3]); void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3]);

@ -122,8 +122,9 @@ void mat3_to_axis_angle(float axis[3], float *angle, float M[3][3]);
void mat4_to_axis_angle(float axis[3], float *angle, float M[4][4]); void mat4_to_axis_angle(float axis[3], float *angle, float M[4][4]);
void quat_to_axis_angle(float axis[3], float *angle, const float q[4]); void quat_to_axis_angle(float axis[3], float *angle, const float q[4]);
void axis_angle_to_mat3_single(float R[3][3], const char axis, const float angle);
void angle_to_mat2(float R[2][2], const float angle); void angle_to_mat2(float R[2][2], const float angle);
void axis_angle_to_mat3_single(float R[3][3], const char axis, const float angle);
void axis_angle_to_mat4_single(float R[4][4], const char axis, const float angle);
void axis_angle_to_quat_single(float q[4], const char axis, const float angle); void axis_angle_to_quat_single(float q[4], const char axis, const float angle);

@ -3917,10 +3917,9 @@ void lookat_m4(float mat[4][4], float vx, float vy, float vz, float px, float py
float sine, cosine, hyp, hyp1, dx, dy, dz; float sine, cosine, hyp, hyp1, dx, dy, dz;
float mat1[4][4]; float mat1[4][4];
unit_m4(mat);
unit_m4(mat1); unit_m4(mat1);
rotate_m4(mat, 'Z', -twist); axis_angle_to_mat4_single(mat, 'Z', -twist);
dx = px - vx; dx = px - vx;
dy = py - vy; dy = py - vy;

@ -1681,53 +1681,47 @@ void translate_m4(float mat[4][4], float Tx, float Ty, float Tz)
} }
/* TODO: enum for axis? */ /* TODO: enum for axis? */
/**
* Rotate a matrix in-place.
*
* \note To create a new rotation matrix see:
* #axis_angle_to_mat4_single, #axis_angle_to_mat3_single, #angle_to_mat2
* (axis & angle args are compatible).
*/
void rotate_m4(float mat[4][4], const char axis, const float angle) void rotate_m4(float mat[4][4], const char axis, const float angle)
{ {
int col; const float angle_cos = cosf(angle);
float temp[4] = {0.0f, 0.0f, 0.0f, 0.0f}; const float angle_sin = sinf(angle);
float cosine, sine;
assert(axis >= 'X' && axis <= 'Z'); assert(axis >= 'X' && axis <= 'Z');
cosine = cosf(angle);
sine = sinf(angle);
switch (axis) { switch (axis) {
case 'X': case 'X':
for (col = 0; col < 4; col++) for (int col = 0; col < 4; col++) {
temp[col] = cosine * mat[1][col] + sine * mat[2][col]; float temp = angle_cos * mat[1][col] + angle_sin * mat[2][col];
for (col = 0; col < 4; col++) { mat[2][col] = -angle_sin * mat[1][col] + angle_cos * mat[2][col];
mat[2][col] = -sine * mat[1][col] + cosine * mat[2][col]; mat[1][col] = temp;
mat[1][col] = temp[col];
} }
break; break;
case 'Y': case 'Y':
for (col = 0; col < 4; col++) for (int col = 0; col < 4; col++) {
temp[col] = cosine * mat[0][col] - sine * mat[2][col]; float temp = angle_cos * mat[0][col] - angle_sin * mat[2][col];
for (col = 0; col < 4; col++) { mat[2][col] = angle_sin * mat[0][col] + angle_cos * mat[2][col];
mat[2][col] = sine * mat[0][col] + cosine * mat[2][col]; mat[0][col] = temp;
mat[0][col] = temp[col];
} }
break; break;
case 'Z': case 'Z':
for (col = 0; col < 4; col++) for (int col = 0; col < 4; col++) {
temp[col] = cosine * mat[0][col] + sine * mat[1][col]; float temp = angle_cos * mat[0][col] + angle_sin * mat[1][col];
for (col = 0; col < 4; col++) { mat[1][col] = -angle_sin * mat[0][col] + angle_cos * mat[1][col];
mat[1][col] = -sine * mat[0][col] + cosine * mat[1][col]; mat[0][col] = temp;
mat[0][col] = temp[col];
} }
break; break;
} }
} }
void rotate_m2(float mat[2][2], const float angle)
{
mat[0][0] = mat[1][1] = cosf(angle);
mat[0][1] = sinf(angle);
mat[1][0] = -mat[0][1];
}
/** /**
* Scale or rotate around a pivot point, * Scale or rotate around a pivot point,
* a convenience function to avoid having to do inline. * a convenience function to avoid having to do inline.

@ -1009,6 +1009,13 @@ void mat4_to_axis_angle(float axis[3], float *angle, float mat[4][4])
quat_to_axis_angle(axis, angle, q); quat_to_axis_angle(axis, angle, q);
} }
void axis_angle_to_mat4_single(float mat[4][4], const char axis, const float angle)
{
float mat3[3][3];
axis_angle_to_mat3_single(mat3, axis, angle);
copy_m4_m3(mat, mat3);
}
/* rotation matrix from a single axis */ /* rotation matrix from a single axis */
void axis_angle_to_mat3_single(float mat[3][3], const char axis, const float angle) void axis_angle_to_mat3_single(float mat[3][3], const char axis, const float angle)
{ {

@ -7706,6 +7706,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
id->lib = main->curlib; id->lib = main->curlib;
id->us = ID_FAKE_USERS(id); id->us = ID_FAKE_USERS(id);
id->icon_id = 0; id->icon_id = 0;
id->newid = NULL; /* Needed because .blend may have been saved with crap value here... */
/* this case cannot be direct_linked: it's just the ID part */ /* this case cannot be direct_linked: it's just the ID part */
if (bhead->code == ID_ID) { if (bhead->code == ID_ID) {

@ -169,6 +169,7 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
float angle; float angle;
mat4_to_loc_rot_size(loc, rot, size, mat); mat4_to_loc_rot_size(loc, rot, size, mat);
mat3_to_vec_roll(rot, NULL, &angle); mat3_to_vec_roll(rot, NULL, &angle);
bone->roll = angle;
} }
copy_v3_v3(bone->head, mat[3]); copy_v3_v3(bone->head, mat[3]);
add_v3_v3v3(bone->tail, bone->head, tail); //tail must be non zero add_v3_v3v3(bone->tail, bone->head, tail); //tail must be non zero

@ -33,11 +33,8 @@
UnitConverter::UnitConverter() : unit(), up_axis(COLLADAFW::FileInfo::Z_UP) UnitConverter::UnitConverter() : unit(), up_axis(COLLADAFW::FileInfo::Z_UP)
{ {
unit_m4(x_up_mat4); axis_angle_to_mat4_single(x_up_mat4, 'Y', -0.5 * M_PI);
rotate_m4(x_up_mat4, 'Y', -0.5 * M_PI); axis_angle_to_mat4_single(y_up_mat4, 'X', 0.5 * M_PI);
unit_m4(y_up_mat4);
rotate_m4(y_up_mat4, 'X', 0.5 * M_PI);
unit_m4(z_up_mat4); unit_m4(z_up_mat4);
unit_m4(scale_mat4); unit_m4(scale_mat4);

@ -48,6 +48,8 @@
#include "util/deg_util_foreach.h" #include "util/deg_util_foreach.h"
#include <cstdio>
namespace DEG { namespace DEG {
string deg_fcurve_id_name(const FCurve *fcu) string deg_fcurve_id_name(const FCurve *fcu)
@ -153,8 +155,8 @@ void deg_graph_build_finalize(Depsgraph *graph)
GHASH_FOREACH_END(); GHASH_FOREACH_END();
ID *id = id_node->id; ID *id = id_node->id;
if (id->tag & LIB_TAG_ID_RECALC_ALL && if ((id->tag & LIB_TAG_ID_RECALC_ALL) &&
id->tag & LIB_TAG_DOIT) (id->tag & LIB_TAG_DOIT))
{ {
id_node->tag_update(graph); id_node->tag_update(graph);
id->tag &= ~LIB_TAG_DOIT; id->tag &= ~LIB_TAG_DOIT;

@ -370,19 +370,26 @@ SubgraphDepsNode *DepsgraphNodeBuilder::build_subgraph(Group *group)
void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob) void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
{ {
if (ob->id.tag & LIB_TAG_DOIT) { const bool has_object = (ob->id.tag & LIB_TAG_DOIT);
IDDepsNode *id_node = m_graph->find_id_node(&ob->id); IDDepsNode *id_node = (has_object)
if (base != NULL) { ? m_graph->find_id_node(&ob->id)
id_node->layers |= base->lay; : add_id_node(&ob->id);
} /* Update node layers.
return; * Do it for both new and existing ID nodes. This is so because several
} * bases might be sharing same object.
ob->id.tag |= LIB_TAG_DOIT; */
IDDepsNode *id_node = add_id_node(&ob->id);
if (base != NULL) { if (base != NULL) {
id_node->layers |= base->lay; id_node->layers |= base->lay;
} }
if (ob == scene->camera) {
/* Camera should always be updated, it used directly by viewport. */
id_node->layers |= (unsigned int)(-1);
}
/* Skip rest of components if the ID node was already there. */
if (has_object) {
return;
}
ob->id.tag |= LIB_TAG_DOIT;
ob->customdata_mask = 0; ob->customdata_mask = 0;
/* Standard components. */ /* Standard components. */

@ -189,16 +189,23 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
/* Transforms props? */ /* Transforms props? */
if (prop) { if (prop) {
const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop); const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop);
/* TODO(sergey): How to optimize this? */
if (strstr(prop_identifier, "location") || if (strstr(prop_identifier, "location") ||
strstr(prop_identifier, "rotation") || strstr(prop_identifier, "rotation") ||
strstr(prop_identifier, "scale")) strstr(prop_identifier, "scale") ||
strstr(prop_identifier, "matrix_"))
{ {
*type = DEPSNODE_TYPE_TRANSFORM; *type = DEPSNODE_TYPE_TRANSFORM;
return true; return true;
} }
else if (strstr(prop_identifier, "data")) {
/* We access object.data, most likely a geometry.
* Might be a bone tho..
*/
*type = DEPSNODE_TYPE_GEOMETRY;
return true;
}
} }
// ...
} }
else if (ptr->type == &RNA_ShapeKey) { else if (ptr->type == &RNA_ShapeKey) {
Key *key = (Key *)ptr->id.data; Key *key = (Key *)ptr->id.data;
@ -371,8 +378,7 @@ DepsRelation *Depsgraph::add_new_relation(OperationDepsNode *from,
if (comp_node->type == DEPSNODE_TYPE_GEOMETRY) { if (comp_node->type == DEPSNODE_TYPE_GEOMETRY) {
IDDepsNode *id_to = to->owner->owner; IDDepsNode *id_to = to->owner->owner;
IDDepsNode *id_from = from->owner->owner; IDDepsNode *id_from = from->owner->owner;
Object *object_to = (Object *)id_to->id; if (id_to != id_from && (id_to->id->tag & LIB_TAG_ID_RECALC_ALL)) {
if (id_to != id_from && (object_to->recalc & OB_RECALC_ALL)) {
if ((id_from->eval_flags & DAG_EVAL_NEED_CPU) == 0) { if ((id_from->eval_flags & DAG_EVAL_NEED_CPU) == 0) {
id_from->tag_update(this); id_from->tag_update(this);
id_from->eval_flags |= DAG_EVAL_NEED_CPU; id_from->eval_flags |= DAG_EVAL_NEED_CPU;

@ -96,6 +96,10 @@ static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *UNUSED(op))
/* Just toggle editmode flag... */ /* Just toggle editmode flag... */
gpd->flag ^= GP_DATA_STROKE_EDITMODE; gpd->flag ^= GP_DATA_STROKE_EDITMODE;
/* recalculate parent matrix */
if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
ED_gpencil_reset_layers_parent(gpd);
}
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL);
WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL); WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);

@ -915,7 +915,7 @@ void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints)
/** /**
* Add randomness to stroke * Add randomness to stroke
* \param gps Stroke data * \param gps Stroke data
* \param brsuh Brush data * \param brush Brush data
*/ */
void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush) void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush)
{ {
@ -997,6 +997,46 @@ void ED_gpencil_parent_location(bGPDlayer *gpl, float diff_mat[4][4])
} }
} }
/* reset parent matrix for all layers */
void ED_gpencil_reset_layers_parent(bGPdata *gpd)
{
bGPDspoint *pt;
int i;
float diff_mat[4][4];
float cur_mat[4][4];
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
if (gpl->parent != NULL) {
/* calculate new matrix */
if ((gpl->partype == PAROBJECT) || (gpl->partype == PARSKEL)) {
invert_m4_m4(cur_mat, gpl->parent->obmat);
}
else if (gpl->partype == PARBONE) {
bPoseChannel *pchan = BKE_pose_channel_find_name(gpl->parent->pose, gpl->parsubstr);
if (pchan) {
float tmp_mat[4][4];
mul_m4_m4m4(tmp_mat, gpl->parent->obmat, pchan->pose_mat);
invert_m4_m4(cur_mat, tmp_mat);
}
}
/* only redo if any change */
if (!equals_m4m4(gpl->inverse, cur_mat)) {
/* first apply current transformation to all strokes */
ED_gpencil_parent_location(gpl, diff_mat);
for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
mul_m4_v3(diff_mat, &pt->x);
}
}
}
/* set new parent matrix */
copy_m4_m4(gpl->inverse, cur_mat);
}
}
}
}
/* ******************************************************** */ /* ******************************************************** */
bool ED_gpencil_stroke_minmax( bool ED_gpencil_stroke_minmax(
const bGPDstroke *gps, const bool use_select, const bGPDstroke *gps, const bool use_select,

@ -185,6 +185,8 @@ int ED_undo_gpencil_step(struct bContext *C, int step, const char *name);
/* get difference matrix using parent */ /* get difference matrix using parent */
void ED_gpencil_parent_location(struct bGPDlayer *gpl, float diff_mat[4][4]); void ED_gpencil_parent_location(struct bGPDlayer *gpl, float diff_mat[4][4]);
/* reset parent matrix for all layers */
void ED_gpencil_reset_layers_parent(struct bGPdata *gpd);
#endif /* __ED_GPENCIL_H__ */ #endif /* __ED_GPENCIL_H__ */

@ -1005,15 +1005,6 @@ DEF_ICON(MATCAP_23)
DEF_ICON(MATCAP_24) DEF_ICON(MATCAP_24)
/* vector icons, VICO_ prefix added */ /* vector icons, VICO_ prefix added */
DEF_VICO(VIEW3D_VEC)
DEF_VICO(EDIT_VEC)
DEF_VICO(EDITMODE_VEC_DEHLT)
DEF_VICO(EDITMODE_VEC_HLT)
DEF_VICO(DISCLOSURE_TRI_RIGHT_VEC)
DEF_VICO(DISCLOSURE_TRI_DOWN_VEC)
DEF_VICO(MOVE_UP_VEC)
DEF_VICO(MOVE_DOWN_VEC)
DEF_VICO(X_VEC)
DEF_VICO(SMALL_TRI_RIGHT_VEC) DEF_VICO(SMALL_TRI_RIGHT_VEC)
DEF_VICO(KEYTYPE_KEYFRAME_VEC) DEF_VICO(KEYTYPE_KEYFRAME_VEC)

@ -181,7 +181,7 @@ enum {
UI_BUT_HAS_SEP_CHAR = (1 << 27), /* but->str contains UI_SEP_CHAR, used for key shortcuts */ UI_BUT_HAS_SEP_CHAR = (1 << 27), /* but->str contains UI_SEP_CHAR, used for key shortcuts */
UI_BUT_UPDATE_DELAY = (1 << 28), /* don't run updates while dragging (needed in rare cases). */ UI_BUT_UPDATE_DELAY = (1 << 28), /* don't run updates while dragging (needed in rare cases). */
UI_BUT_TEXTEDIT_UPDATE = (1 << 29), /* when widget is in textedit mode, update value on each char stroke */ UI_BUT_TEXTEDIT_UPDATE = (1 << 29), /* when widget is in textedit mode, update value on each char stroke */
UI_BUT_SEARCH_UNLINK = (1 << 30), /* show unlink for search button */ UI_BUT_VALUE_CLEAR = (1 << 30), /* show 'x' icon to clear/unlink value of text or search button */
}; };
#define UI_PANEL_WIDTH 340 #define UI_PANEL_WIDTH 340

@ -1987,22 +1987,29 @@ uiBut *ui_but_drag_multi_edit_get(uiBut *but)
/** \name Check to show extra icons /** \name Check to show extra icons
* *
* Extra icons are shown on the right hand side of buttons. * Extra icons are shown on the right hand side of buttons.
* This could (should!) definitely become more generic, but for now this is good enough.
* \{ */ * \{ */
static bool ui_but_icon_extra_is_visible_text_clear(const uiBut *but)
{
BLI_assert(but->type == UI_BTYPE_TEXT);
return ((but->flag & UI_BUT_VALUE_CLEAR) && but->drawstr && but->drawstr[0]);
}
static bool ui_but_icon_extra_is_visible_search_unlink(const uiBut *but) static bool ui_but_icon_extra_is_visible_search_unlink(const uiBut *but)
{ {
BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); BLI_assert(but->type == UI_BTYPE_SEARCH_MENU);
return ((but->editstr == NULL) && return ((but->editstr == NULL) &&
(but->drawstr[0] != '\0') && (but->drawstr[0] != '\0') &&
(but->flag & UI_BUT_SEARCH_UNLINK)); (but->flag & UI_BUT_VALUE_CLEAR));
} }
static bool ui_but_icon_extra_is_visible_eyedropper(uiBut *but) static bool ui_but_icon_extra_is_visible_search_eyedropper(uiBut *but)
{ {
StructRNA *type; StructRNA *type;
short idcode; short idcode;
BLI_assert(but->type == UI_BTYPE_SEARCH_MENU && (but->flag & UI_BUT_SEARCH_UNLINK)); BLI_assert(but->type == UI_BTYPE_SEARCH_MENU && (but->flag & UI_BUT_VALUE_CLEAR));
if (but->rnaprop == NULL) { if (but->rnaprop == NULL) {
return false; return false;
@ -2011,21 +2018,31 @@ static bool ui_but_icon_extra_is_visible_eyedropper(uiBut *but)
type = RNA_property_pointer_type(&but->rnapoin, but->rnaprop); type = RNA_property_pointer_type(&but->rnapoin, but->rnaprop);
idcode = RNA_type_to_ID_code(type); idcode = RNA_type_to_ID_code(type);
return ((but->editstr == NULL) && return ((but->editstr == NULL) &&
(idcode == ID_OB || OB_DATA_SUPPORT_ID(idcode))); (idcode == ID_OB || OB_DATA_SUPPORT_ID(idcode)));
} }
uiButExtraIconType ui_but_icon_extra_get(uiBut *but) uiButExtraIconType ui_but_icon_extra_get(uiBut *but)
{ {
if ((but->flag & UI_BUT_SEARCH_UNLINK) == 0) { switch (but->type) {
/* pass */ case UI_BTYPE_TEXT:
} if (ui_but_icon_extra_is_visible_text_clear(but)) {
else if (ui_but_icon_extra_is_visible_search_unlink(but)) { return UI_BUT_ICONEXTRA_CLEAR;
return UI_BUT_ICONEXTRA_UNLINK; }
} break;
else if (ui_but_icon_extra_is_visible_eyedropper(but)) { case UI_BTYPE_SEARCH_MENU:
return UI_BUT_ICONEXTRA_EYEDROPPER; if ((but->flag & UI_BUT_VALUE_CLEAR) == 0) {
/* pass */
}
else if (ui_but_icon_extra_is_visible_search_unlink(but)) {
return UI_BUT_ICONEXTRA_CLEAR;
}
else if (ui_but_icon_extra_is_visible_search_eyedropper(but)) {
return UI_BUT_ICONEXTRA_EYEDROPPER;
}
break;
default:
break;
} }
return UI_BUT_ICONEXTRA_NONE; return UI_BUT_ICONEXTRA_NONE;

@ -748,7 +748,7 @@ static int datadropper_poll(bContext *C)
if ((CTX_wm_window(C) != NULL) && if ((CTX_wm_window(C) != NULL) &&
(but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) && (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
(but->type == UI_BTYPE_SEARCH_MENU) && (but->type == UI_BTYPE_SEARCH_MENU) &&
(but->flag & UI_BUT_SEARCH_UNLINK)) (but->flag & UI_BUT_VALUE_CLEAR))
{ {
if (prop && RNA_property_type(prop) == PROP_POINTER) { if (prop && RNA_property_type(prop) == PROP_POINTER) {
StructRNA *type = RNA_property_pointer_type(&ptr, prop); StructRNA *type = RNA_property_pointer_type(&ptr, prop);

@ -2554,6 +2554,18 @@ void ui_but_text_password_hide(char password_str[UI_MAX_PASSWORD_STR], uiBut *bu
} }
} }
static void ui_but_text_clear(bContext *C, uiBut *but, uiHandleButtonData *data)
{
/* most likely NULL, but let's check, and give it temp zero string */
if (!data->str) {
data->str = MEM_callocN(1, "temp str");
}
data->str[0] = 0;
ui_apply_but_TEX(C, but, data);
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
/* ************* in-button text selection/editing ************* */ /* ************* in-button text selection/editing ************* */
@ -3820,6 +3832,21 @@ static int ui_do_but_KEYEVT(
return WM_UI_HANDLER_CONTINUE; return WM_UI_HANDLER_CONTINUE;
} }
static bool ui_but_is_mouse_over_icon_extra(const ARegion *region, uiBut *but, const int mouse_xy[2])
{
int x = mouse_xy[0], y = mouse_xy[1];
rcti icon_rect;
BLI_assert(ui_but_icon_extra_get(but) != UI_BUT_ICONEXTRA_NONE);
ui_window_to_block(region, but->block, &x, &y);
BLI_rcti_rctf_copy(&icon_rect, &but->rect);
icon_rect.xmin = icon_rect.xmax - (BLI_rcti_size_y(&icon_rect));
return BLI_rcti_isect_pt(&icon_rect, x, y);
}
static int ui_do_but_TEX( static int ui_do_but_TEX(
bContext *C, uiBlock *block, uiBut *but, bContext *C, uiBlock *block, uiBut *but,
uiHandleButtonData *data, const wmEvent *event) uiHandleButtonData *data, const wmEvent *event)
@ -3833,7 +3860,14 @@ static int ui_do_but_TEX(
/* pass */ /* pass */
} }
else { else {
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); const bool has_icon_extra = ui_but_icon_extra_get(but) == UI_BUT_ICONEXTRA_CLEAR;
if (has_icon_extra && ui_but_is_mouse_over_icon_extra(data->region, but, &event->x)) {
ui_but_text_clear(C, but, data);
}
else {
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
}
return WM_UI_HANDLER_BREAK; return WM_UI_HANDLER_BREAK;
} }
} }
@ -3854,47 +3888,29 @@ static int ui_do_but_SEARCH_UNLINK(
bContext *C, uiBlock *block, uiBut *but, bContext *C, uiBlock *block, uiBut *but,
uiHandleButtonData *data, const wmEvent *event) uiHandleButtonData *data, const wmEvent *event)
{ {
uiButExtraIconType extra_icon_type; const uiButExtraIconType extra_icon_type = ui_but_icon_extra_get(but);
const bool has_icon_extra = (extra_icon_type != UI_BUT_ICONEXTRA_NONE);
/* unlink icon is on right */ /* unlink icon is on right */
if ((ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY)) && if ((ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY)) &&
((extra_icon_type = ui_but_icon_extra_get(but)) != UI_BUT_ICONEXTRA_NONE)) (has_icon_extra == true) &&
(ui_but_is_mouse_over_icon_extra(data->region, but, &event->x) == true))
{ {
ARegion *ar = data->region; /* doing this on KM_PRESS calls eyedropper after clicking unlink icon */
rcti rect; if (event->val == KM_RELEASE) {
int x = event->x, y = event->y; /* unlink */
if (extra_icon_type == UI_BUT_ICONEXTRA_CLEAR) {
ui_window_to_block(ar, but->block, &x, &y); ui_but_text_clear(C, but, data);
}
BLI_rcti_rctf_copy(&rect, &but->rect); /* eyedropper */
else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) {
rect.xmin = rect.xmax - (BLI_rcti_size_y(&rect)); WM_operator_name_call(C, "UI_OT_eyedropper_id", WM_OP_INVOKE_DEFAULT, NULL);
/* handle click on unlink/eyedropper icon */ }
if (BLI_rcti_isect_pt(&rect, x, y)) { else {
/* doing this on KM_PRESS calls eyedropper after clicking unlink icon */ BLI_assert(0);
if (event->val == KM_RELEASE) {
/* unlink */
if (extra_icon_type == UI_BUT_ICONEXTRA_UNLINK) {
/* most likely NULL, but let's check, and give it temp zero string */
if (data->str == NULL) {
data->str = MEM_callocN(1, "temp str");
}
data->str[0] = 0;
ui_apply_but_TEX(C, but, data);
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
/* eyedropper */
else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) {
WM_operator_name_call(C, "UI_OT_eyedropper_id", WM_OP_INVOKE_DEFAULT, NULL);
}
else {
BLI_assert(0);
}
} }
return WM_UI_HANDLER_BREAK;
} }
return WM_UI_HANDLER_BREAK;
} }
return ui_do_but_TEX(C, block, but, data, event); return ui_do_but_TEX(C, block, but, data, event);
} }
@ -7069,7 +7085,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
case UI_BTYPE_TEXT: case UI_BTYPE_TEXT:
case UI_BTYPE_SEARCH_MENU: case UI_BTYPE_SEARCH_MENU:
if ((but->type == UI_BTYPE_SEARCH_MENU) && if ((but->type == UI_BTYPE_SEARCH_MENU) &&
(but->flag & UI_BUT_SEARCH_UNLINK)) (but->flag & UI_BUT_VALUE_CLEAR))
{ {
retval = ui_do_but_SEARCH_UNLINK(C, block, but, data, event); retval = ui_do_but_SEARCH_UNLINK(C, block, but, data, event);
if (retval & WM_UI_HANDLER_BREAK) { if (retval & WM_UI_HANDLER_BREAK) {

@ -127,7 +127,7 @@ enum {
* (e.g. 'x' icon in search menu) - used with ui_but_icon_extra_get */ * (e.g. 'x' icon in search menu) - used with ui_but_icon_extra_get */
typedef enum uiButExtraIconType { typedef enum uiButExtraIconType {
UI_BUT_ICONEXTRA_NONE = 1, UI_BUT_ICONEXTRA_NONE = 1,
UI_BUT_ICONEXTRA_UNLINK, UI_BUT_ICONEXTRA_CLEAR,
UI_BUT_ICONEXTRA_EYEDROPPER, UI_BUT_ICONEXTRA_EYEDROPPER,
} uiButExtraIconType; } uiButExtraIconType;

@ -1659,7 +1659,7 @@ void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRN
but->rnasearchprop = searchprop; but->rnasearchprop = searchprop;
but->drawflag |= UI_BUT_ICON_LEFT | UI_BUT_TEXT_LEFT; but->drawflag |= UI_BUT_ICON_LEFT | UI_BUT_TEXT_LEFT;
if (RNA_property_is_unlink(prop)) { if (RNA_property_is_unlink(prop)) {
but->flag |= UI_BUT_SEARCH_UNLINK; but->flag |= UI_BUT_VALUE_CLEAR;
} }
if (RNA_property_type(prop) == PROP_ENUM) { if (RNA_property_type(prop) == PROP_ENUM) {

@ -851,7 +851,7 @@ static void ui_searchbox_select(bContext *C, ARegion *ar, uiBut *but, int step)
} }
else { else {
/* only let users step into an 'unset' state for unlink buttons */ /* only let users step into an 'unset' state for unlink buttons */
data->active = (but->flag & UI_BUT_SEARCH_UNLINK) ? -1 : 0; data->active = (but->flag & UI_BUT_VALUE_CLEAR) ? -1 : 0;
} }
} }
@ -922,8 +922,8 @@ bool ui_searchbox_apply(uiBut *but, ARegion *ar)
return true; return true;
} }
else if (but->flag & UI_BUT_SEARCH_UNLINK) { else if (but->flag & UI_BUT_VALUE_CLEAR) {
/* It is valid for _UNLINK flavor to have no active element (it's a valid way to unlink). */ /* It is valid for _VALUE_CLEAR flavor to have no active element (it's a valid way to unlink). */
but->editstr[0] = '\0'; but->editstr[0] = '\0';
return true; return true;

@ -302,7 +302,10 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
break; break;
case UI_ID_LOCAL: case UI_ID_LOCAL:
if (id) { if (id) {
if (id_make_local(CTX_data_main(C), id, false, false)) { Main *bmain = CTX_data_main(C);
if (id_make_local(bmain, id, false, false)) {
BKE_main_id_clear_newpoins(bmain);
/* reassign to get get proper updates/notifiers */ /* reassign to get get proper updates/notifiers */
idptr = RNA_property_pointer_get(&template->ptr, template->prop); idptr = RNA_property_pointer_get(&template->ptr, template->prop);
RNA_property_pointer_set(&template->ptr, template->prop, idptr); RNA_property_pointer_set(&template->ptr, template->prop, idptr);

@ -119,6 +119,10 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind
else else
but = uiDefButR_prop(block, UI_BTYPE_TEXT, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL); but = uiDefButR_prop(block, UI_BTYPE_TEXT, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
PropertySubType subtype = RNA_property_subtype(prop);
if (!(ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME) || (block->flag & UI_BLOCK_LIST_ITEM))) {
UI_but_flag_enable(but, UI_BUT_VALUE_CLEAR);
}
if (RNA_property_flag(prop) & PROP_TEXTEDIT_UPDATE) { if (RNA_property_flag(prop) & PROP_TEXTEDIT_UPDATE) {
UI_but_flag_enable(but, UI_BUT_TEXTEDIT_UPDATE); UI_but_flag_enable(but, UI_BUT_TEXTEDIT_UPDATE);
} }

@ -1513,10 +1513,10 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
/* draws text and icons for buttons */ /* draws text and icons for buttons */
static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect) static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect)
{ {
const uiButExtraIconType extra_icon_type = ui_but_icon_extra_get(but);
const bool show_menu_icon = ui_but_draw_menu_icon(but); const bool show_menu_icon = ui_but_draw_menu_icon(but);
float alpha = (float)wcol->text[3] / 255.0f; float alpha = (float)wcol->text[3] / 255.0f;
char password_str[UI_MAX_DRAW_STR]; char password_str[UI_MAX_DRAW_STR];
uiButExtraIconType extra_icon_type;
ui_but_text_password_hide(password_str, but, false); ui_but_text_password_hide(password_str, but, false);
@ -1582,15 +1582,13 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
rect->xmax -= (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect; rect->xmax -= (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect;
} }
/* unlink icon for this button type */ /* extra icons, e.g. 'x' icon to clear text or icon for eyedropper */
if ((but->type == UI_BTYPE_SEARCH_MENU) && if (extra_icon_type != UI_BUT_ICONEXTRA_NONE) {
((extra_icon_type = ui_but_icon_extra_get(but)) != UI_BUT_ICONEXTRA_NONE))
{
rcti temp = *rect; rcti temp = *rect;
temp.xmin = temp.xmax - (BLI_rcti_size_y(rect) * 1.08f); temp.xmin = temp.xmax - (BLI_rcti_size_y(rect) * 1.08f);
if (extra_icon_type == UI_BUT_ICONEXTRA_UNLINK) { if (extra_icon_type == UI_BUT_ICONEXTRA_CLEAR) {
widget_draw_icon(but, ICON_X, alpha, &temp, false); widget_draw_icon(but, ICON_X, alpha, &temp, false);
} }
else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) { else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) {

@ -2140,7 +2140,7 @@ static float snap_v2_angle(float r[2], const float v[2], const float v_ref[2], f
normalize_v2_v2(v_unit, v); normalize_v2_v2(v_unit, v);
angle = angle_signed_v2v2(v_unit, v_ref); angle = angle_signed_v2v2(v_unit, v_ref);
angle_delta = (roundf(angle / angle_snap) * angle_snap) - angle; angle_delta = (roundf(angle / angle_snap) * angle_snap) - angle;
rotate_m2(m2, angle_delta); angle_to_mat2(m2, angle_delta);
mul_v2_m2v2(r, m2, v); mul_v2_m2v2(r, m2, v);
return angle + angle_delta; return angle + angle_delta;

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