elif builder.startswith('win'):
if builder.endswith('_vc2015'):
if builder.startswith('win64'):
- cmake_options.extend(['-G', 'Visual Studio 14 2015 Win64'])
+ cmake_options.extend(['-G', 'Visual Studio 14 2015 Win64', b'-DCUDA_NVCC_FLAGS="-ccbin C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\amd64\\"'])
elif builder.startswith('win32'):
bits = 32
- cmake_options.extend(['-G', 'Visual Studio 14 2015'])
+ cmake_options.extend(['-G', 'Visual Studio 14 2015', b'-DCUDA_NVCC_FLAGS="-ccbin C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\"'])
else:
if builder.startswith('win64'):
cmake_options.extend(['-G', 'Visual Studio 12 2013 Win64'])
--python-exit-code 1 \
--python $SPHINXBASE/sphinx_doc_gen.py
- if (($? == 1)) ; then
+ if (($? != 0)) ; then
echo "Generating documentation failed, aborting"
exit 1
fi
--- /dev/null
+Project: WC Width
+URL: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+License: ICS
+Upstream version: 2007-05-26
+Local modifications: None
def use_branched_path(context):
cscene = context.scene.cycles
- device_type = context.user_preferences.system.compute_device_type
- return (cscene.progressive == 'BRANCHED_PATH' and device_type != 'OPENCL')
+ return (cscene.progressive == 'BRANCHED_PATH' and not use_opencl(context))
def use_sample_all_lights(context):
col = split.column()
sub = col.column(align=True)
- sub.label(text="Displacment:")
+ sub.label(text="Displacement:")
sub.prop(cdata, "displacement_method", text="")
col = split.column()
foreach(Object *ob, objects) {
if(params.top_level) {
+ if(!ob->is_traceable()) {
+ continue;
+ }
if(!ob->mesh->is_instanced()) {
num_alloc_references += ob->mesh->num_triangles();
num_alloc_references += count_curve_segments(ob->mesh);
foreach(Object *ob, objects) {
if(params.top_level) {
+ if(!ob->is_traceable()) {
+ continue;
+ }
if(!ob->mesh->is_instanced())
add_reference_mesh(bounds, center, ob->mesh, i);
else
/* 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) {
+ info.description += " (Display)";
info.display_device = true;
display_devices.push_back(info);
}
OUTPUT ${cuda_cubin}
COMMAND ${CUDA_NVCC_EXECUTABLE}
-arch=${arch}
+ ${CUDA_NVCC_FLAGS}
-m${CUDA_BITS}
--cubin ${CMAKE_CURRENT_SOURCE_DIR}/kernels/cuda/kernel.cu
-o ${CMAKE_CURRENT_BINARY_DIR}/${cuda_cubin}
#endif
{
#ifdef __KERNEL_GPU__
- float4 a = tri_b - tri_a, b = tri_c - tri_a;
- if(len_squared(make_float3(a.y*b.z - a.z*b.y,
- a.z*b.x - a.x*b.z,
- a.x*b.y - a.y*b.x)) == 0.0f)
- {
+ if(A == B && B == C) {
return false;
}
#endif
-
/* Normalize U, V, W, and T. */
const float inv_det = 1.0f / det;
isect->prim = triAddr;
}
num_possible++;
- float t = -(dot(P, dir) - dot(lightpos, dir)) / dot(direction, dir);
- if(t <= 1e-4f) {
- /* Either behind the portal or too close. */
- continue;
- }
-
float4 data1 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 1);
float4 data2 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 2);
float3 axisu = make_float3(data1.y, data1.z, data1.w);
float3 axisv = make_float3(data2.y, data2.z, data2.w);
- float3 hit = P + t*direction;
- float3 inplane = hit - lightpos;
- /* Skip if the the ray doesn't pass through portal. */
- if(fabsf(dot(inplane, axisu) / dot(axisu, axisu)) > 0.5f)
- continue;
- if(fabsf(dot(inplane, axisv) / dot(axisv, axisv)) > 0.5f)
+ if(!ray_quad_intersect(P, direction, 1e-4f, FLT_MAX, lightpos, axisu, axisv, dir, NULL, NULL))
continue;
portal_pdf += area_light_sample(P, &lightpos, axisu, axisv, 0.0f, 0.0f, false);
float3 light_P = make_float3(data0.y, data0.z, data0.w);
- if(!ray_quad_intersect(P, D, t,
- light_P, axisu, axisv, &ls->P, &ls->t))
+ if(!ray_quad_intersect(P, D, 0.0f, t,
+ light_P, axisu, axisv, Ng, &ls->P, &ls->t))
{
return false;
}
# else
Intersection isect;
int step = 0;
+ float3 Pend = ray->P + ray->D*ray->t;
while(step < 2 * VOLUME_STACK_SIZE &&
scene_intersect_volume(kg,
&volume_ray,
/* Move ray forward. */
volume_ray.P = ray_offset(stack_sd->P, -stack_sd->Ng);
- volume_ray.t -= stack_sd->ray_length;
+ if(volume_ray.t != FLT_MAX) {
+ volume_ray.D = normalize_len(Pend - volume_ray.P, &volume_ray.t);
+ }
++step;
}
# endif
bool MixNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *optimized)
{
- if(type != ustring("Mix")) {
+ if(type != NODE_MIX_BLEND) {
return false;
}
return times;
}
+bool Object::is_traceable()
+{
+ /* Mesh itself can be empty,can skip all such objects. */
+ if (bounds.size() == make_float3(0.0f, 0.0f, 0.0f)) {
+ return false;
+ }
+ /* TODO(sergey): Check for mesh vertices/curves. visibility flags. */
+ return true;
+}
+
/* Object Manager */
ObjectManager::ObjectManager()
void apply_transform(bool apply_to_motion);
vector<float> motion_times();
+
+ /* Check whether object is traceable and it worth adding it to
+ * kernel scene.
+ */
+ bool is_traceable();
};
/* Object Manager */
util_simd.cpp
util_system.cpp
util_task.cpp
+ util_thread.cpp
util_time.cpp
util_transform.cpp
+ util_windows.cpp
)
if(NOT CYCLES_STANDALONE_REPOSITORY)
return true;
}
-ccl_device bool ray_quad_intersect(float3 ray_P, float3 ray_D, float ray_t,
- float3 quad_P, float3 quad_u, float3 quad_v,
+ccl_device bool ray_quad_intersect(float3 ray_P, float3 ray_D, float ray_mint, float ray_maxt,
+ float3 quad_P, float3 quad_u, float3 quad_v, float3 quad_n,
float3 *isect_P, float *isect_t)
{
- float3 v0 = quad_P - quad_u*0.5f - quad_v*0.5f;
- float3 v1 = quad_P + quad_u*0.5f - quad_v*0.5f;
- float3 v2 = quad_P + quad_u*0.5f + quad_v*0.5f;
- float3 v3 = quad_P - quad_u*0.5f + quad_v*0.5f;
+ float t = -(dot(ray_P, quad_n) - dot(quad_P, quad_n)) / dot(ray_D, quad_n);
+ if(t < ray_mint || t > ray_maxt)
+ return false;
- if(ray_triangle_intersect(ray_P, ray_D, ray_t, v0, v1, v2, isect_P, isect_t))
- return true;
- else if(ray_triangle_intersect(ray_P, ray_D, ray_t, v0, v2, v3, isect_P, isect_t))
- return true;
-
- return false;
+ float3 hit = ray_P + t*ray_D;
+ float3 inplane = hit - quad_P;
+ if(fabsf(dot(inplane, quad_u) / dot(quad_u, quad_u)) > 0.5f)
+ return false;
+ if(fabsf(dot(inplane, quad_v) / dot(quad_v, quad_v)) > 0.5f)
+ return false;
+
+ if(isect_P) *isect_P = hit;
+ if(isect_t) *isect_t = t;
+
+ return true;
}
/* projections */
*/
#include "util_system.h"
+
#include "util_debug.h"
+#include "util_logging.h"
#include "util_types.h"
#include "util_string.h"
CCL_NAMESPACE_BEGIN
-int system_cpu_thread_count()
+int system_cpu_group_count()
{
- static uint count = 0;
-
- if(count > 0)
- return count;
+#ifdef _WIN32
+ util_windows_init_numa_groups();
+ return GetActiveProcessorGroupCount();
+#else
+ /* TODO(sergey): Need to adopt for other platforms. */
+ return 1;
+#endif
+}
+int system_cpu_group_thread_count(int group)
+{
+ /* TODO(sergey): Need make other platforms aware of groups. */
#ifdef _WIN32
- SYSTEM_INFO info;
- GetSystemInfo(&info);
- count = (uint)info.dwNumberOfProcessors;
+ util_windows_init_numa_groups();
+ return GetActiveProcessorCount(group);
#elif defined(__APPLE__)
+ (void)group;
+ int count;
size_t len = sizeof(count);
int mib[2] = { CTL_HW, HW_NCPU };
-
sysctl(mib, 2, &count, &len, NULL, 0);
+ return count;
#else
- count = (uint)sysconf(_SC_NPROCESSORS_ONLN);
+ (void)group;
+ return sysconf(_SC_NPROCESSORS_ONLN);
#endif
+}
+
+int system_cpu_thread_count()
+{
+ static uint count = 0;
- if(count < 1)
+ if(count > 0) {
+ return count;
+ }
+
+ int max_group = system_cpu_group_count();
+ VLOG(1) << "Detected " << max_group << " CPU groups.";
+ for(int group = 0; group < max_group; ++group) {
+ int num_threads = system_cpu_group_thread_count(group);
+ VLOG(1) << "Group " << group
+ << " has " << num_threads << " threads.";
+ count += num_threads;
+ }
+
+ if(count < 1) {
count = 1;
+ }
return count;
}
CCL_NAMESPACE_BEGIN
+/* Get number of available CPU groups. */
+int system_cpu_group_count();
+
+/* Get number of threads/processors in the specified group. */
+int system_cpu_group_thread_count(int group);
+
+/* Get total number of threads in all groups. */
int system_cpu_thread_count();
+
string system_cpu_brand_string();
int system_cpu_bits();
bool system_cpu_support_sse2();
#include "util_debug.h"
#include "util_foreach.h"
+#include "util_logging.h"
#include "util_system.h"
#include "util_task.h"
#include "util_time.h"
/* automatic number of threads */
num_threads = system_cpu_thread_count();
}
+ VLOG(1) << "Creating pool of " << num_threads << " threads.";
/* launch threads that will be waiting for work */
threads.resize(num_threads);
- for(size_t i = 0; i < threads.size(); i++)
- threads[i] = new thread(function_bind(&TaskScheduler::thread_run, i + 1));
+ int num_groups = system_cpu_group_count();
+ int thread_index = 0;
+ for(int group = 0; group < num_groups; ++group) {
+ /* NOTE: That's not really efficient from threading point of view,
+ * but it is simple to read and it doesn't make sense to use more
+ * user-specified threads than logical threads anyway.
+ */
+ int num_group_threads = (group == num_groups - 1)
+ ? (threads.size() - thread_index)
+ : system_cpu_group_thread_count(group);
+ for(int group_thread = 0;
+ group_thread < num_group_threads && thread_index < threads.size();
+ ++group_thread, ++thread_index)
+ {
+ threads[thread_index] = new thread(function_bind(&TaskScheduler::thread_run,
+ thread_index + 1),
+ group);
+ }
+ }
}
users++;
--- /dev/null
+/*
+ * 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.
+ */
+
+#include "util_thread.h"
+
+#include "util_system.h"
+#include "util_windows.h"
+
+CCL_NAMESPACE_BEGIN
+
+thread::thread(function<void(void)> run_cb, int group)
+ : run_cb_(run_cb),
+ joined_(false),
+ group_(group)
+{
+ pthread_create(&pthread_id_, NULL, run, (void*)this);
+}
+
+thread::~thread()
+{
+ if(!joined_) {
+ join();
+ }
+}
+
+void *thread::run(void *arg)
+{
+ thread *self = (thread*)(arg);
+ if(self->group_ != -1) {
+#ifdef _WIN32
+ HANDLE thread_handle = GetCurrentThread();
+ GROUP_AFFINITY group_affinity = { 0 };
+ int num_threads = system_cpu_group_thread_count(self->group_);
+ group_affinity.Group = self->group_;
+ group_affinity.Mask = (num_threads == 64)
+ ? -1
+ : (1ull << num_threads) - 1;
+ if(SetThreadGroupAffinity(thread_handle, &group_affinity, NULL) == 0) {
+ fprintf(stderr, "Error setting thread affinity.\n");
+ }
+#endif
+ }
+ self->run_cb_();
+ return NULL;
+}
+
+bool thread::join()
+{
+ joined_ = true;
+ return pthread_join(pthread_id_, NULL) == 0;
+}
+
+CCL_NAMESPACE_END
class thread {
public:
- thread(function<void(void)> run_cb_)
+ thread(function<void(void)> run_cb, int group = -1);
+ ~thread();
- {
- joined = false;
- run_cb = run_cb_;
-
- pthread_create(&pthread_id, NULL, run, (void*)this);
- }
-
- ~thread()
- {
- if(!joined)
- join();
- }
-
- static void *run(void *arg)
- {
- ((thread*)arg)->run_cb();
- return NULL;
- }
-
- bool join()
- {
- joined = true;
- return pthread_join(pthread_id, NULL) == 0;
- }
+ static void *run(void *arg);
+ bool join();
protected:
- function<void(void)> run_cb;
- pthread_t pthread_id;
- bool joined;
+ function<void(void)> run_cb_;
+ pthread_t pthread_id_;
+ bool joined_;
+ int group_;
};
/* Own wrapper around pthread's spin lock to make it's use easier. */
--- /dev/null
+/*
+ * 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.
+ */
+
+#include "util_windows.h"
+
+#ifdef _WIN32
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef _M_X64
+# include <VersionHelpers.h>
+#endif
+
+#if _WIN32_WINNT < 0x0601
+tGetActiveProcessorGroupCount *GetActiveProcessorGroupCount;
+tGetActiveProcessorCount *GetActiveProcessorCount;
+tSetThreadGroupAffinity *SetThreadGroupAffinity;
+#endif
+
+static WORD GetActiveProcessorGroupCount_stub()
+{
+ return 1;
+}
+
+static DWORD GetActiveProcessorCount_stub(WORD /*GroupNumber*/)
+{
+ SYSTEM_INFO info;
+ GetSystemInfo(&info);
+ return info.dwNumberOfProcessors;
+}
+
+static BOOL SetThreadGroupAffinity_stub(
+ HANDLE /*hThread*/,
+ const GROUP_AFFINITY * /*GroupAffinity*/,
+ PGROUP_AFFINITY /*PreviousGroupAffinity*/)
+{
+ return TRUE;
+}
+
+static bool supports_numa()
+{
+#ifndef _M_X64
+ return false;
+#else
+ return IsWindows7OrGreater();
+#endif
+}
+
+void util_windows_init_numa_groups()
+{
+ static bool initialized = false;
+ if(initialized) {
+ return;
+ }
+ initialized = true;
+#if _WIN32_WINNT < 0x0601
+ if(!supports_numa()) {
+ /* Use stubs on platforms which doesn't have rean NUMA/Groups. */
+ GetActiveProcessorGroupCount = GetActiveProcessorGroupCount_stub;
+ GetActiveProcessorCount = GetActiveProcessorCount_stub;
+ SetThreadGroupAffinity = SetThreadGroupAffinity_stub;
+ return;
+ }
+ HMODULE kernel = GetModuleHandleA("kernel32.dll");
+# define READ_SYMBOL(sym) sym = (t##sym*)GetProcAddress(kernel, #sym)
+ READ_SYMBOL(GetActiveProcessorGroupCount);
+ READ_SYMBOL(GetActiveProcessorCount);
+ READ_SYMBOL(SetThreadGroupAffinity);
+# undef READ_SUMBOL
+#endif
+}
+
+CCL_NAMESPACE_END
+
+#endif /* _WIN32 */
#include <windows.h>
+CCL_NAMESPACE_BEGIN
+
+#if _WIN32_WINNT < 0x0601
+typedef WORD tGetActiveProcessorGroupCount();
+typedef DWORD tGetActiveProcessorCount(WORD GroupNumber);
+typedef BOOL tSetThreadGroupAffinity(HANDLE hThread,
+ const GROUP_AFFINITY *GroupAffinity,
+ PGROUP_AFFINITY PreviousGroupAffinity);
+
+extern tGetActiveProcessorGroupCount *GetActiveProcessorGroupCount;
+extern tGetActiveProcessorCount *GetActiveProcessorCount;
+extern tSetThreadGroupAffinity *SetThreadGroupAffinity;
+#endif
+
+/* Make sure NUMA and processor groups API is initialized. */
+void util_windows_init_numa_groups();
+
+CCL_NAMESPACE_END
+
#endif /* WIN32 */
#endif /* __UTIL_WINDOWS_H__ */
"vertices",
# Merged words
- "addon", "addons",
+ #~ "addon", "addons",
"antialiasing",
"arcsine", "arccosine", "arctangent",
"autoclip",
"localview",
"lookup", "lookups",
"mathutils",
+ "micropolygon",
"midlevel",
"midground",
"mixdown",
"multires", "multiresolution",
"multisampling",
"multitexture",
+ "multithreaded",
"multiuser",
"multiview",
"namespace",
# Blender terms
"audaspace",
"bbone",
+ "bendy", # bones
"bmesh",
"breakdowner",
"bspline",
"wpaint",
"uvwarp",
- # Algorithm names
+ # Algorithm/library names
"ashikhmin", # Ashikhmin-Shirley
"beckmann",
+ "blosc",
"catmull",
"catrom",
"chebychev",
header="#b4b4b4"
header_text="#000000"
header_text_hi="#ffffff"
- button="#727272ff"
+ button="#b4b4b457"
button_title="#000000"
button_text="#000000"
button_text_hi="#ffffff"
return prop_new
- prop = unique_name(item.keys())
+ prop = unique_name(
+ {*item.keys(),
+ *type(item).bl_rna.properties.keys(),
+ })
item[prop] = 1.0
rna_idprop_ui_prop_update(item, prop)
WindowManager.addon_filter = EnumProperty(
items=addon_filter_items,
name="Category",
- description="Filter addons by category",
+ description="Filter add-ons by category",
)
WindowManager.addon_support = EnumProperty(
sub = row.row(align=True)
sub.active = has_vgroup
sub.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT')
+ subcol.prop(md, "mix_limit")
def CORRECTIVE_SMOOTH(self, layout, ob, md):
is_bind = md.is_bind
/* TODO(sergey): This is mainly a temp public function. */
struct FCurve;
-bool BKE_animsys_execute_fcurve(struct PointerRNA *ptr, struct AnimMapper *remap, struct FCurve *fcu);
+bool BKE_animsys_execute_fcurve(struct PointerRNA *ptr, struct AnimMapper *remap, struct FCurve *fcu, float curval);
/* ------------ Specialized API --------------- */
/* There are a few special tools which require these following functions. They are NOT to be used
/* evaluate fcurve */
float evaluate_fcurve(struct FCurve *fcu, float evaltime);
/* evaluate fcurve and store value */
-void calculate_fcurve(struct FCurve *fcu, float ctime);
+float calculate_fcurve(struct FCurve *fcu, float evaltime);
/* ************* F-Curve Samples API ******************** */
struct Scene *scene,
struct Object *ob);
+void BKE_object_eval_proxy_backlink(struct EvaluationContext *eval_ctx, struct Object *ob);
+
void BKE_object_handle_data_update(struct EvaluationContext *eval_ctx,
struct Scene *scene,
struct Object *ob);
DynStr *ds = BLI_dynstr_new();
const char *postfixPtr = oldNamePtr + oldNameLen;
char *newPath = NULL;
- char oldChar;
-
+
/* add the part of the string that goes up to the start of the prefix */
if (prefixPtr > oldpath) {
- oldChar = prefixPtr[0];
- prefixPtr[0] = 0;
- BLI_dynstr_append(ds, oldpath);
- prefixPtr[0] = oldChar;
+ BLI_dynstr_nappend(ds, oldpath, prefixPtr - oldpath);
}
/* add the prefix */
}
/* Simple replacement based data-setting of the FCurve using RNA */
-bool BKE_animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu)
+bool BKE_animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu, float curval)
{
char *path = NULL;
bool free_path = false;
/* write value to setting */
if (path)
- ok = animsys_write_rna_setting(ptr, path, fcu->array_index, fcu->curval);
+ ok = animsys_write_rna_setting(ptr, path, fcu->array_index, curval);
/* free temp path-info */
if (free_path)
if ((fcu->grp == NULL) || (fcu->grp->flag & AGRP_MUTED) == 0) {
/* check if this curve should be skipped */
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
- calculate_fcurve(fcu, ctime);
- BKE_animsys_execute_fcurve(ptr, remap, fcu);
+ const float curval = calculate_fcurve(fcu, ctime);
+ BKE_animsys_execute_fcurve(ptr, remap, fcu, curval);
}
}
}
/* evaluate this using values set already in other places
* NOTE: for 'layering' option later on, we should check if we should remove old value before adding
* new to only be done when drivers only changed */
- calculate_fcurve(fcu, ctime);
- ok = BKE_animsys_execute_fcurve(ptr, NULL, fcu);
+ const float curval = calculate_fcurve(fcu, ctime);
+ ok = BKE_animsys_execute_fcurve(ptr, NULL, fcu, curval);
/* clear recalc flag */
driver->flag &= ~DRIVER_FLAG_RECALC;
for (fcu = agrp->channels.first; (fcu) && (fcu->grp == agrp); fcu = fcu->next) {
/* check if this curve should be skipped */
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
- calculate_fcurve(fcu, ctime);
- BKE_animsys_execute_fcurve(ptr, remap, fcu);
+ const float curval = calculate_fcurve(fcu, ctime);
+ BKE_animsys_execute_fcurve(ptr, remap, fcu, curval);
}
}
}
* NOTE: for 'layering' option later on, we should check if we should remove old value before adding
* new to only be done when drivers only changed */
//printf("\told val = %f\n", fcu->curval);
- calculate_fcurve(fcu, eval_ctx->ctime);
- ok = BKE_animsys_execute_fcurve(&id_ptr, NULL, fcu);
+ const float curval = calculate_fcurve(fcu, eval_ctx->ctime);
+ ok = BKE_animsys_execute_fcurve(&id_ptr, NULL, fcu, curval);
//printf("\tnew val = %f\n", fcu->curval);
/* clear recalc flag */
BLI_assert((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0);
for (path_cmp = U.autoexec_paths.first; path_cmp; path_cmp = path_cmp->next) {
- if ((path_cmp->flag & USER_PATHCMP_GLOB)) {
+ if (path_cmp->path[0] == '\0') {
+ /* pass */
+ }
+ else if ((path_cmp->flag & USER_PATHCMP_GLOB)) {
if (fnmatch(path_cmp->path, path, fnmatch_flags) == 0) {
return true;
}
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
int size = (ups->flag & UNIFIED_PAINT_SIZE) ? ups->size : brush->size;
- return (int)((float)size * U.pixelsize);
+ return size;
}
int BKE_brush_use_locked_size(const Scene *scene, const Brush *brush)
emDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData);
}
+static void emdm_pass_attrib_update_uniforms(const DMVertexAttribs *attribs)
+{
+ int i;
+ if (attribs->totorco) {
+ glUniform1i(attribs->orco.gl_info_index, 0);
+ }
+ for (i = 0; i < attribs->tottface; i++) {
+ glUniform1i(attribs->tface[i].gl_info_index, 0);
+ }
+ for (i = 0; i < attribs->totmcol; i++) {
+ glUniform1i(attribs->mcol[i].gl_info_index, GPU_ATTR_INFO_SRGB);
+ }
+
+ for (i = 0; i < attribs->tottang; i++) {
+ glUniform1i(attribs->tang[i].gl_info_index, 0);
+ }
+}
+
/**
* \note
*
glTexCoord3fv(orco);
else
glVertexAttrib3fv(attribs->orco.gl_index, orco);
- glUniform1i(attribs->orco.gl_info_index, 0);
}
for (i = 0; i < attribs->tottface; i++) {
const float *uv;
glTexCoord2fv(uv);
else
glVertexAttrib2fv(attribs->tface[i].gl_index, uv);
- glUniform1i(attribs->tface[i].gl_info_index, 0);
}
for (i = 0; i < attribs->totmcol; i++) {
float col[4];
col[0] = 0.0f; col[1] = 0.0f; col[2] = 0.0f; col[3] = 0.0f;
}
glVertexAttrib4fv(attribs->mcol[i].gl_index, col);
- glUniform1i(attribs->mcol[i].gl_info_index, GPU_ATTR_INFO_SRGB);
}
for (i = 0; i < attribs->tottang; i++) {
tang = zero;
}
glVertexAttrib4fv(attribs->tang[i].gl_index, tang);
- glUniform1i(attribs->tang[i].gl_info_index, 0);
}
}
do_draw = setMaterial(matnr = new_matnr, &gattribs);
if (do_draw) {
DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
+ emdm_pass_attrib_update_uniforms(&attribs);
if (UNLIKELY(attribs.tottang && bm->elem_index_dirty & BM_LOOP)) {
BM_mesh_elem_index_ensure(bm, BM_LOOP);
}
{
int ret = 0;
- if (eff->pd && eff->pd->shape==PFIELD_SHAPE_SURFACE && eff->surmd) {
+ /* In case surface object is in Edit mode when loading the .blend, surface modifier is never executed
+ * and bvhtree never built, see T48415. */
+ if (eff->pd && eff->pd->shape==PFIELD_SHAPE_SURFACE && eff->surmd && eff->surmd->bvhtree) {
/* closest point in the object surface is an effector */
float vec[3];
}
/* Calculate the value of the given F-Curve at the given frame, and set its curval */
-void calculate_fcurve(FCurve *fcu, float ctime)
+float calculate_fcurve(FCurve *fcu, float evaltime)
{
/* only calculate + set curval (overriding the existing value) if curve has
* any data which warrants this...
list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE))
{
/* calculate and set curval (evaluates driver too if necessary) */
- fcu->curval = evaluate_fcurve(fcu, ctime);
+ float curval = evaluate_fcurve(fcu, evaltime);
+ fcu->curval = curval; /* debug display only, not thread safe! */
+ return curval;
+ }
+ else {
+ return 0.0f;
}
}
#include "BLT_translation.h"
+#include "BKE_library.h"
#include "BKE_idcode.h"
typedef struct {
/* plural need to match rna_main.c's MainCollectionDef */
/* WARNING! Keep it in sync with i18n contexts in BLT_translation.h */
static IDType idtypes[] = {
+ /** ID's directly below must all be in #Main, and be kept in sync with #MAX_LIBARRAY (membership, not order) */
{ ID_AC, "Action", "actions", BLT_I18NCONTEXT_ID_ACTION, IDTYPE_FLAGS_ISLINKABLE },
{ ID_AR, "Armature", "armatures", BLT_I18NCONTEXT_ID_ARMATURE, IDTYPE_FLAGS_ISLINKABLE },
{ ID_BR, "Brush", "brushes", BLT_I18NCONTEXT_ID_BRUSH, IDTYPE_FLAGS_ISLINKABLE },
{ ID_CU, "Curve", "curves", BLT_I18NCONTEXT_ID_CURVE, IDTYPE_FLAGS_ISLINKABLE },
{ ID_GD, "GPencil", "grease_pencil", BLT_I18NCONTEXT_ID_GPENCIL, IDTYPE_FLAGS_ISLINKABLE }, /* rename gpencil */
{ ID_GR, "Group", "groups", BLT_I18NCONTEXT_ID_GROUP, IDTYPE_FLAGS_ISLINKABLE },
- { ID_ID, "ID", "ids", BLT_I18NCONTEXT_ID_ID, 0 }, /* plural is fake */
{ ID_IM, "Image", "images", BLT_I18NCONTEXT_ID_IMAGE, IDTYPE_FLAGS_ISLINKABLE },
{ ID_IP, "Ipo", "ipos", "", IDTYPE_FLAGS_ISLINKABLE }, /* deprecated */
{ ID_KE, "Key", "shape_keys", BLT_I18NCONTEXT_ID_SHAPEKEY, 0 },
{ ID_VF, "VFont", "fonts", BLT_I18NCONTEXT_ID_VFONT, IDTYPE_FLAGS_ISLINKABLE },
{ ID_WO, "World", "worlds", BLT_I18NCONTEXT_ID_WORLD, IDTYPE_FLAGS_ISLINKABLE },
{ ID_WM, "WindowManager", "window_managers", BLT_I18NCONTEXT_ID_WINDOWMANAGER, 0 },
+
+ /** Keep last, not an ID exactly, only include for completeness */
+ { ID_ID, "ID", "ids", BLT_I18NCONTEXT_ID_ID, 0 }, /* plural is fake */
};
+/* -1 for ID_ID */
+BLI_STATIC_ASSERT((ARRAY_SIZE(idtypes) - 1 == MAX_LIBARRAY), "Missing IDType");
+
static IDType *idtype_from_name(const char *str)
{
int i = ARRAY_SIZE(idtypes);
ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME);
}
+
+void BKE_object_eval_proxy_backlink(EvaluationContext *UNUSED(eval_ctx), Object *ob)
+{
+ if (ob->proxy) {
+ ob->proxy->proxy_from = ob;
+ }
+}
BLI_gset_free(node->bm_other_verts, NULL);
}
}
+ GPU_free_pbvh_buffer_multires(&bvh->grid_common_gpu_buffer);
if (bvh->deformed) {
if (bvh->verts) {
node->totprim,
bvh->grid_hidden,
bvh->gridkey.grid_size,
- &bvh->gridkey);
+ &bvh->gridkey, &bvh->grid_common_gpu_buffer);
break;
case PBVH_FACES:
node->draw_buffers =
const DMFlagMat *grid_flag_mats;
int totgrid;
BLI_bitmap **grid_hidden;
+ /* index_buf of GPU_PBVH_Buffers can be the same for all 'fully drawn' nodes (same size).
+ * Previously was stored in a static var in gpu_buffer.c, but this breaks in case we handle several different
+ * objects in sculpt mode with different sizes at the same time, so now storing that common gpu buffer
+ * in an opaque pointer per pbvh. See T47637. */
+ struct GridCommonGPUBuffer *grid_common_gpu_buffer;
/* Only used during BVH build and update,
* don't need to remain valid after */
gh->flag = flag;
ghash_buckets_reset(gh, nentries_reserve);
- gh->entrypool = BLI_mempool_create(GHASH_ENTRY_SIZE(flag & GHASH_FLAG_IS_GSET), 0, 64, BLI_MEMPOOL_NOP);
+ gh->entrypool = BLI_mempool_create(GHASH_ENTRY_SIZE(flag & GHASH_FLAG_IS_GSET), 64, 64, BLI_MEMPOOL_NOP);
return gh;
}
const GHashPair *A = a;
const GHashPair *B = b;
- return (BLI_ghashutil_ptrcmp(A->first, B->first) &&
+ return (BLI_ghashutil_ptrcmp(A->first, B->first) ||
BLI_ghashutil_ptrcmp(A->second, B->second));
}
*/
void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
{
- BLI_freenode *ret;
+ if (UNLIKELY(iter->curchunk == NULL)) {
+ return NULL;
+ }
+ const unsigned int esize = iter->pool->esize;
+ BLI_freenode *curnode = POINTER_OFFSET(CHUNK_DATA(iter->curchunk), (esize * iter->curindex));
+ BLI_freenode *ret;
do {
- if (LIKELY(iter->curchunk)) {
- ret = (BLI_freenode *)(((char *)CHUNK_DATA(iter->curchunk)) + (iter->pool->esize * iter->curindex));
+ ret = curnode;
+
+ if (++iter->curindex != iter->pool->pchunk) {
+ curnode = POINTER_OFFSET(curnode, esize);
}
else {
- return NULL;
- }
-
- if (UNLIKELY(++iter->curindex == iter->pool->pchunk)) {
iter->curindex = 0;
iter->curchunk = iter->curchunk->next;
+ if (iter->curchunk == NULL) {
+ return NULL;
+ }
+ curnode = CHUNK_DATA(iter->curchunk);
}
} while (ret->freeword == FREEWORD);
/* pre-calculated */
size_t chunk_byte_size;
+ /* min/max limits (inclusive) */
size_t chunk_byte_size_min;
+ size_t chunk_byte_size_max;
size_t accum_read_ahead_bytes;
#ifdef USE_HASH_TABLE_ACCUMULATE
if (MIN2(chunk_prev->data_len, chunk_curr->data_len) < info->chunk_byte_size_min) {
const size_t data_merge_len = chunk_prev->data_len + chunk_curr->data_len;
/* we could pass, but no need */
- if (data_merge_len <= (info->chunk_byte_size * BCHUNK_SIZE_MAX_MUL)) {
+ if (data_merge_len <= info->chunk_byte_size_max) {
/* we have enough space to merge */
/* remove last from linklist */
}
#endif /* USE_MERGE_CHUNKS */
+
+/**
+ * Split length into 2 values
+ * \param r_data_trim_len: Length which is aligned to the #BArrayInfo.chunk_byte_size
+ * \param r_data_last_chunk_len: The remaining bytes.
+ *
+ * \note This function ensures the size of \a r_data_last_chunk_len
+ * is larger than #BArrayInfo.chunk_byte_size_min.
+ */
+static void bchunk_list_calc_trim_len(
+ const BArrayInfo *info, const size_t data_len,
+ size_t *r_data_trim_len, size_t *r_data_last_chunk_len)
+{
+ size_t data_last_chunk_len = 0;
+ size_t data_trim_len = data_len;
+
+#ifdef USE_MERGE_CHUNKS
+ /* avoid creating too-small chunks
+ * more efficient then merging after */
+ if (data_len > info->chunk_byte_size) {
+ data_last_chunk_len = (data_trim_len % info->chunk_byte_size);
+ data_trim_len = data_trim_len - data_last_chunk_len;
+ if (data_last_chunk_len) {
+ if (data_last_chunk_len < info->chunk_byte_size_min) {
+ /* may be zero and thats OK */
+ data_trim_len -= info->chunk_byte_size;
+ data_last_chunk_len += info->chunk_byte_size;
+ }
+ }
+ }
+ else {
+ data_trim_len = 0;
+ data_last_chunk_len = data_len;
+ }
+
+ BLI_assert((data_trim_len == 0) || (data_trim_len >= info->chunk_byte_size));
+#else
+ data_last_chunk_len = (data_trim_len % info->chunk_byte_size);
+ data_trim_len = data_trim_len - data_last_chunk_len;
+#endif
+
+ BLI_assert(data_trim_len + data_last_chunk_len == data_len);
+
+ *r_data_trim_len = data_trim_len;
+ *r_data_last_chunk_len = data_last_chunk_len;
+}
+
/**
* Append and don't manage merging small chunks.
*/
return chunk;
}
+/**
+ * \note This is for writing single chunks,
+ * use #bchunk_list_append_data_n when writing large blocks of memory into many chunks.
+ */
static void bchunk_list_append_data(
const BArrayInfo *info, BArrayMemory *bs_mem,
BChunkList *chunk_list,
const ubyte *data, const size_t data_len)
{
BLI_assert(data_len != 0);
+
// printf("data_len: %d\n", data_len);
#ifdef USE_MERGE_CHUNKS
+ BLI_assert(data_len <= info->chunk_byte_size_max);
+
if (!BLI_listbase_is_empty(&chunk_list->chunk_refs)) {
BChunkRef *cref = chunk_list->chunk_refs.last;
BChunk *chunk_prev = cref->link;
#endif
}
+/**
+ * Similar to #bchunk_list_append_data, but handle multiple chunks.
+ * Use for adding arrays of arbitrary sized memory at once.
+ *
+ * \note This function takes care not to perform redundant chunk-merging checks,
+ * so we can write succesive fixed size chunks quickly.
+ */
+static void bchunk_list_append_data_n(
+ const BArrayInfo *info, BArrayMemory *bs_mem,
+ BChunkList *chunk_list,
+ const ubyte *data, size_t data_len)
+{
+ size_t data_trim_len, data_last_chunk_len;
+ bchunk_list_calc_trim_len(info, data_len, &data_trim_len, &data_last_chunk_len);
+
+ if (data_trim_len != 0) {
+ size_t i_prev;
+
+ {
+ const size_t i = info->chunk_byte_size;
+ bchunk_list_append_data(info, bs_mem, chunk_list, data, i);
+ i_prev = i;
+ }
+
+ while (i_prev != data_trim_len) {
+ const size_t i = i_prev + info->chunk_byte_size;
+ BChunk *chunk = bchunk_new_copydata(bs_mem, &data[i_prev], i - i_prev);
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+ i_prev = i;
+ }
+
+ if (data_last_chunk_len) {
+ BChunk *chunk = bchunk_new_copydata(bs_mem, &data[i_prev], data_last_chunk_len);
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+ // i_prev = data_len; /* UNUSED */
+ }
+ }
+ else {
+ /* if we didn't write any chunks previously,
+ * we may need to merge with the last. */
+ if (data_last_chunk_len) {
+ bchunk_list_append_data(info, bs_mem, chunk_list, data, data_last_chunk_len);
+ // i_prev = data_len; /* UNUSED */
+ }
+ }
+
+#ifdef USE_MERGE_CHUNKS
+ if (data_len > info->chunk_byte_size) {
+ BLI_assert(((BChunkRef *)chunk_list->chunk_refs.last)->link->data_len >= info->chunk_byte_size_min);
+ }
+#endif
+}
+
static void bchunk_list_append(
const BArrayInfo *info, BArrayMemory *bs_mem,
BChunkList *chunk_list,
{
BLI_assert(BLI_listbase_is_empty(&chunk_list->chunk_refs));
- size_t data_last_chunk_len = 0;
- size_t data_trim_len = data_len;
-
-#ifdef USE_MERGE_CHUNKS
- /* avoid creating too-small chunks
- * more efficient then merging after */
- if (data_len > info->chunk_byte_size) {
- data_last_chunk_len = (data_trim_len % info->chunk_byte_size);
- data_trim_len = data_trim_len - data_last_chunk_len;
- if (data_last_chunk_len) {
- if (data_last_chunk_len < info->chunk_byte_size_min) {
- /* may be zero and thats OK */
- data_trim_len -= info->chunk_byte_size;
- data_last_chunk_len += info->chunk_byte_size;
- }
- }
- }
- else {
- data_trim_len = 0;
- data_last_chunk_len = data_len;
- }
-#else
- data_last_chunk_len = (data_trim_len % info->chunk_byte_size);
- data_trim_len = data_trim_len - data_last_chunk_len;
-#endif
-
-
- BLI_assert(data_trim_len + data_last_chunk_len == data_len);
+ size_t data_trim_len, data_last_chunk_len;
+ bchunk_list_calc_trim_len(info, data_len, &data_trim_len, &data_last_chunk_len);
size_t i_prev = 0;
- while (i_prev < data_trim_len) {
+ while (i_prev != data_trim_len) {
const size_t i = i_prev + info->chunk_byte_size;
BChunk *chunk = bchunk_new_copydata(bs_mem, &data[i_prev], i - i_prev);
bchunk_list_append_only(bs_mem, chunk_list, chunk);
if (cref_found != NULL) {
BLI_assert(i < data_len);
if (i != i_prev) {
- size_t i_step = MIN2(i_prev + info->chunk_byte_size, data_len);
- BLI_assert(i_step <= data_len);
-
- while (i_prev != i) {
- i_step = MIN2(i_step, i);
- const ubyte *data_slice = &data[i_prev];
- const size_t data_slice_len = i_step - i_prev;
- /* First add all previous chunks! */
- i_prev += data_slice_len;
- bchunk_list_append_data(info, bs_mem, chunk_list, data_slice, data_slice_len);
- BLI_assert(i_prev <= data_len);
- ASSERT_CHUNKLIST_SIZE(chunk_list, i_prev);
- ASSERT_CHUNKLIST_DATA(chunk_list, data);
- i_step += info->chunk_byte_size;
- }
+ bchunk_list_append_data_n(info, bs_mem, chunk_list, &data[i_prev], i - i_prev);
+ i_prev = i;
}
/* now add the reference chunk */
*
* Trailing chunks, no matches found in table lookup above.
* Write all new data. */
- BLI_assert(i_prev <= data_len);
- while (i_prev != data_len) {
- size_t i = i_prev + info->chunk_byte_size;
- i = MIN2(i, data_len);
- BLI_assert(i != i_prev);
- bchunk_list_append_data(info, bs_mem, chunk_list, &data[i_prev], i - i_prev);
- ASSERT_CHUNKLIST_DATA(chunk_list, data);
- i_prev = i;
+ if (i_prev != data_len) {
+ bchunk_list_append_data_n(info, bs_mem, chunk_list, &data[i_prev], data_len - i_prev);
+ i_prev = data_len;
}
BLI_assert(i_prev == data_len);
bs->info.chunk_byte_size = chunk_count * stride;
#ifdef USE_MERGE_CHUNKS
bs->info.chunk_byte_size_min = MAX2(1u, chunk_count / BCHUNK_SIZE_MIN_DIV) * stride;
+ bs->info.chunk_byte_size_max = (chunk_count * BCHUNK_SIZE_MAX_MUL) * stride;
#endif
#ifdef USE_HASH_TABLE_ACCUMULATE
if (!(bchunk_list_size(chunk_list) == chunk_list->total_size)) {
return false;
}
+
+ if (BLI_listbase_count(&chunk_list->chunk_refs) != (int)chunk_list->chunk_refs_len) {
+ return false;
+ }
+
+#ifdef USE_MERGE_CHUNKS
+ /* ensure we merge all chunks that could be merged */
+ if (chunk_list->total_size > bs->info.chunk_byte_size_min) {
+ for (BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ if (cref->link->data_len < bs->info.chunk_byte_size_min) {
+ return false;
+ }
+ }
+ }
+#endif
}
{
/***/
typedef struct OldNew {
- void *old, *newp;
+ const void *old;
+ void *newp;
int nr;
} OldNew;
typedef struct OldNewMap {
OldNew *entries;
int nentries, entriessize;
- int sorted;
+ bool sorted;
int lasthit;
} OldNewMap;
static void oldnewmap_sort(FileData *fd)
{
+ BLI_assert(fd->libmap->sorted == false);
qsort(fd->libmap->entries, fd->libmap->nentries, sizeof(OldNew), verg_oldnewmap);
fd->libmap->sorted = 1;
}
/* nr is zero for data, and ID code for libdata */
-static void oldnewmap_insert(OldNewMap *onm, void *oldaddr, void *newaddr, int nr)
+static void oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr)
{
OldNew *entry;
entry->nr = nr;
}
-void blo_do_versions_oldnewmap_insert(OldNewMap *onm, void *oldaddr, void *newaddr, int nr)
+void blo_do_versions_oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr)
{
oldnewmap_insert(onm, oldaddr, newaddr, nr);
}
return -1;
}
-static void *oldnewmap_lookup_and_inc(OldNewMap *onm, void *addr, bool increase_users)
+static void *oldnewmap_lookup_and_inc(OldNewMap *onm, const void *addr, bool increase_users)
{
int i;
}
/* for libdata, nr has ID code, no increment */
-static void *oldnewmap_liblookup(OldNewMap *onm, void *addr, void *lib)
+static void *oldnewmap_liblookup(OldNewMap *onm, const void *addr, const void *lib)
{
if (addr == NULL) {
return NULL;
/* lasthit works fine for non-libdata, linking there is done in same sequence as writing */
if (onm->sorted) {
- OldNew entry_s, *entry;
-
- entry_s.old = addr;
-
- entry = bsearch(&entry_s, onm->entries, onm->nentries, sizeof(OldNew), verg_oldnewmap);
+ const OldNew entry_s = {.old = addr};
+ OldNew *entry = bsearch(&entry_s, onm->entries, onm->nentries, sizeof(OldNew), verg_oldnewmap);
if (entry) {
ID *id = entry->newp;
}
}
-static void split_libdata(ListBase *lb, Main *first)
+static void split_libdata(ListBase *lb_src, Main **lib_main_array, const unsigned int lib_main_array_len)
{
- ListBase *lbn;
- ID *id, *idnext;
- Main *mainvar;
-
- id = lb->first;
- while (id) {
+ for (ID *id = lb_src->first, *idnext; id; id = idnext) {
idnext = id->next;
+
if (id->lib) {
- mainvar = first;
- while (mainvar) {
- if (mainvar->curlib == id->lib) {
- lbn= which_libbase(mainvar, GS(id->name));
- BLI_remlink(lb, id);
- BLI_addtail(lbn, id);
- break;
- }
- mainvar = mainvar->next;
+ if (((unsigned int)id->lib->temp_index < lib_main_array_len) &&
+ /* this check should never fail, just incase 'id->lib' is a dangling pointer. */
+ (lib_main_array[id->lib->temp_index]->curlib == id->lib))
+ {
+ Main *mainvar = lib_main_array[id->lib->temp_index];
+ ListBase *lb_dst = which_libbase(mainvar, GS(id->name));
+ BLI_remlink(lb_src, id);
+ BLI_addtail(lb_dst, id);
+ }
+ else {
+ printf("%s: invalid library for '%s'\n", __func__, id->name);
+ BLI_assert(0);
}
- if (mainvar == NULL) printf("error split_libdata\n");
}
- id = idnext;
}
}
void blo_split_main(ListBase *mainlist, Main *main)
{
- ListBase *lbarray[MAX_LIBARRAY];
- Library *lib;
- int i;
-
mainlist->first = mainlist->last = main;
main->next = NULL;
if (BLI_listbase_is_empty(&main->library))
return;
- for (lib = main->library.first; lib; lib = lib->id.next) {
+ /* (Library.temp_index -> Main), lookup table */
+ const unsigned int lib_main_array_len = BLI_listbase_count(&main->library);
+ Main **lib_main_array = MEM_mallocN(lib_main_array_len * sizeof(*lib_main_array), __func__);
+
+ int i = 0;
+ for (Library *lib = main->library.first; lib; lib = lib->id.next, i++) {
Main *libmain = BKE_main_new();
libmain->curlib = lib;
BLI_addtail(mainlist, libmain);
+ lib->temp_index = i;
+ lib_main_array[i] = libmain;
}
+ ListBase *lbarray[MAX_LIBARRAY];
i = set_listbasepointers(main, lbarray);
- while (i--)
- split_libdata(lbarray[i], main->next);
+ while (i--) {
+ split_libdata(lbarray[i], lib_main_array, lib_main_array_len);
+ }
+
+ MEM_freeN(lib_main_array);
}
static void read_file_version(FileData *fd, Main *main)
/* ************** OLD POINTERS ******************* */
-static void *newdataadr(FileData *fd, void *adr) /* only direct databocks */
+static void *newdataadr(FileData *fd, const void *adr) /* only direct databocks */
{
return oldnewmap_lookup_and_inc(fd->datamap, adr, true);
}
* fcurve group pointer and keeps lasthit optimal for linking all further
* fcurves.
*/
-static void *newdataadr_ex(FileData *fd, void *adr, bool increase_lasthit) /* only direct databocks */
+static void *newdataadr_ex(FileData *fd, const void *adr, bool increase_lasthit) /* only direct databocks */
{
if (increase_lasthit) {
return newdataadr(fd, adr);
}
}
-static void *newdataadr_no_us(FileData *fd, void *adr) /* only direct databocks */
+static void *newdataadr_no_us(FileData *fd, const void *adr) /* only direct databocks */
{
return oldnewmap_lookup_and_inc(fd->datamap, adr, false);
}
-static void *newglobadr(FileData *fd, void *adr) /* direct datablocks with global linking */
+static void *newglobadr(FileData *fd, const void *adr) /* direct datablocks with global linking */
{
return oldnewmap_lookup_and_inc(fd->globmap, adr, true);
}
-static void *newimaadr(FileData *fd, void *adr) /* used to restore image data after undo */
+static void *newimaadr(FileData *fd, const void *adr) /* used to restore image data after undo */
{
if (fd->imamap && adr)
return oldnewmap_lookup_and_inc(fd->imamap, adr, true);
return NULL;
}
-static void *newmclipadr(FileData *fd, void *adr) /* used to restore movie clip data after undo */
+static void *newmclipadr(FileData *fd, const void *adr) /* used to restore movie clip data after undo */
{
if (fd->movieclipmap && adr)
return oldnewmap_lookup_and_inc(fd->movieclipmap, adr, true);
return NULL;
}
-static void *newsoundadr(FileData *fd, void *adr) /* used to restore sound data after undo */
+static void *newsoundadr(FileData *fd, const void *adr) /* used to restore sound data after undo */
{
if (fd->soundmap && adr)
return oldnewmap_lookup_and_inc(fd->soundmap, adr, true);
return NULL;
}
-static void *newpackedadr(FileData *fd, void *adr) /* used to restore packed data after undo */
+static void *newpackedadr(FileData *fd, const void *adr) /* used to restore packed data after undo */
{
if (fd->packedmap && adr)
return oldnewmap_lookup_and_inc(fd->packedmap, adr, true);
}
-static void *newlibadr(FileData *fd, void *lib, void *adr) /* only lib data */
+static void *newlibadr(FileData *fd, const void *lib, const void *adr) /* only lib data */
{
return oldnewmap_liblookup(fd->libmap, adr, lib);
}
-void *blo_do_versions_newlibadr(FileData *fd, void *lib, void *adr) /* only lib data */
+void *blo_do_versions_newlibadr(FileData *fd, const void *lib, const void *adr) /* only lib data */
{
return newlibadr(fd, lib, adr);
}
-static void *newlibadr_us(FileData *fd, void *lib, void *adr) /* increases user number */
+static void *newlibadr_us(FileData *fd, const void *lib, const void *adr) /* increases user number */
{
ID *id = newlibadr(fd, lib, adr);
return id;
}
-void *blo_do_versions_newlibadr_us(FileData *fd, void *lib, void *adr) /* increases user number */
+void *blo_do_versions_newlibadr_us(FileData *fd, const void *lib, const void *adr) /* increases user number */
{
return newlibadr_us(fd, lib, adr);
}
-static void change_idid_adr_fd(FileData *fd, void *old, void *new)
+static void change_idid_adr_fd(FileData *fd, const void *old, void *new)
{
int i;
+ /* use a binary search if we have a sorted libmap, for now it's not needed. */
+ BLI_assert(fd->libmap->sorted == false);
+
for (i = 0; i < fd->libmap->nentries; i++) {
OldNew *entry = &fd->libmap->entries[i];
return bhead;
}
-static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID **r_id)
+static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short tag, ID **r_id)
{
/* this routine reads a libblock and its direct data. Use link functions to connect it all
*/
/* In undo case, most libs and linked data should be kept as is from previous state (see BLO_read_from_memfile).
* However, some needed by the snapshot being read may have been removed in previous one, and would go missing.
* This leads e.g. to desappearing objects in some undo/redo case, see T34446.
- * That means we have to carefully check whether current lib or libdata already exits in old main, if it does
- * we merely copy it over into new main area, otherwise we have to do a full read of that bhead... */
+ * That means we have to carefully check whether current lib or libdata already exits in old main, if it does
+ * we merely copy it over into new main area, otherwise we have to do a full read of that bhead... */
if (fd->memfile && ELEM(bhead->code, ID_LI, ID_ID)) {
const char *idname = bhead_id_name(fd, bhead);
if (!id)
return blo_nextbhead(fd, bhead);
- id->tag = flag | LIB_TAG_NEED_LINK;
+ id->tag = tag | LIB_TAG_NEED_LINK;
id->lib = main->curlib;
id->us = ID_FAKE_USERS(id);
id->icon_id = 0;
}
}
-static ID *create_placeholder(Main *mainvar, const char *idname, const short flag)
+static ID *create_placeholder(Main *mainvar, const char *idname, const short tag)
{
const short idcode = GS(idname);
ListBase *lb = which_libbase(mainvar, idcode);
memcpy(ph_id->name, idname, sizeof(ph_id->name));
BKE_libblock_init_empty(ph_id);
ph_id->lib = mainvar->curlib;
- ph_id->tag = flag | LIB_TAG_MISSING;
+ ph_id->tag = tag | LIB_TAG_MISSING;
ph_id->us = ID_FAKE_USERS(ph_id);
ph_id->icon_id = 0;
/* ************* READ LIBRARY ************** */
-static int mainvar_count_libread_blocks(Main *mainvar)
+static int mainvar_id_tag_any_check(Main *mainvar, const short tag)
{
ListBase *lbarray[MAX_LIBARRAY];
- int a, tot = 0;
+ int a;
a = set_listbasepointers(mainvar, lbarray);
while (a--) {
ID *id;
for (id = lbarray[a]->first; id; id = id->next) {
- if (id->tag & LIB_TAG_READ)
- tot++;
+ if (id->tag & tag) {
+ return true;
+ }
}
}
- return tot;
+ return false;
}
static void read_libraries(FileData *basefd, ListBase *mainlist)
/* test 1: read libdata */
mainptr= mainl->next;
while (mainptr) {
- int tot = mainvar_count_libread_blocks(mainptr);
-
- // printf("found LIB_TAG_READ %s\n", mainptr->curlib->name);
- if (tot) {
+ if (mainvar_id_tag_any_check(mainptr, LIB_TAG_READ)) {
+ // printf("found LIB_TAG_READ %s\n", mainptr->curlib->name);
+
FileData *fd = mainptr->curlib->filedata;
if (fd == NULL) {
void blo_reportf_wrap(struct ReportList *reports, ReportType type, const char *format, ...) ATTR_PRINTF_FORMAT(3, 4);
-void blo_do_versions_oldnewmap_insert(struct OldNewMap *onm, void *oldaddr, void *newaddr, int nr);
-void *blo_do_versions_newlibadr(struct FileData *fd, void *lib, void *adr);
-void *blo_do_versions_newlibadr_us(struct FileData *fd, void *lib, void *adr);
+void blo_do_versions_oldnewmap_insert(struct OldNewMap *onm, const void *oldaddr, void *newaddr, int nr);
+void *blo_do_versions_newlibadr(struct FileData *fd, const void *lib, const void *adr);
+void *blo_do_versions_newlibadr_us(struct FileData *fd, const void *lib, const void *adr);
struct PartEff *blo_do_version_give_parteff_245(struct Object *ob);
void blo_do_version_old_trackto_to_constraints(struct Object *ob);
}
}
}
- }
- {
for (Camera *camera = main->camera.first; camera != NULL; camera = camera->id.next) {
if (camera->stereo.pole_merge_angle_from == 0.0f &&
camera->stereo.pole_merge_angle_to == 0.0f)
camera->stereo.pole_merge_angle_to = DEG2RAD(75.0f);
}
}
+
+ if (!DNA_struct_elem_find(fd->filesdna, "NormalEditModifierData", "float", "mix_limit")) {
+ Object *ob;
+
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ ModifierData *md;
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_NormalEdit) {
+ NormalEditModifierData *nemd = (NormalEditModifierData *)md;
+ nemd->mix_limit = DEG2RADF(180.0f);
+ }
+ }
+ }
+ }
}
}
// #include "bevdebug.c"
+/* some flags to re-enable old behavior for a while, in case fixes broke things not caught by regression tests */
+static int bev_debug_flags = 0;
+#define DEBUG_OLD_PLANE_SPECIAL (bev_debug_flags & 1)
+#define DEBUG_OLD_PROJ_TO_PERP_PLANE (bev_debug_flags & 2)
+#define DEBUG_OLD_FLAT_MID (bev_debug_flags & 4)
+
/* Make a new BoundVert of the given kind, insert it at the end of the circular linked
* list with entry point bv->boundstart, and return it. */
static BoundVert *add_new_bound_vert(MemArena *mem_arena, VMesh *vm, const float co[3])
sub_v3_v3v3(pro->proj_dir, e->e->v1->co, e->e->v2->co);
normalize_v3(pro->proj_dir);
project_to_edge(e->e, co1, co2, pro->midco);
- /* put arc endpoints on plane with normal proj_dir, containing midco */
- add_v3_v3v3(co3, co1, pro->proj_dir);
- if (!isect_line_plane_v3(pro->coa, co1, co3, pro->midco, pro->proj_dir)) {
- /* shouldn't happen */
- copy_v3_v3(pro->coa, co1);
+ if (DEBUG_OLD_PROJ_TO_PERP_PLANE) {
+ /* put arc endpoints on plane with normal proj_dir, containing midco */
+ add_v3_v3v3(co3, co1, pro->proj_dir);
+ if (!isect_line_plane_v3(pro->coa, co1, co3, pro->midco, pro->proj_dir)) {
+ /* shouldn't happen */
+ copy_v3_v3(pro->coa, co1);
+ }
+ add_v3_v3v3(co3, co2, pro->proj_dir);
+ if (!isect_line_plane_v3(pro->cob, co2, co3, pro->midco, pro->proj_dir)) {
+ /* shouldn't happen */
+ copy_v3_v3(pro->cob, co2);
+ }
}
- add_v3_v3v3(co3, co2, pro->proj_dir);
- if (!isect_line_plane_v3(pro->cob, co2, co3, pro->midco, pro->proj_dir)) {
- /* shouldn't happen */
+ else {
+ copy_v3_v3(pro->coa, co1);
copy_v3_v3(pro->cob, co2);
}
/* default plane to project onto is the one with triangle co1 - midco - co2 in it */
if (l <= BEVEL_EPSILON_BIG) {
/* co1 - midco -co2 are collinear.
* Should be case that beveled edge is coplanar with two boundary verts.
+ * We want to move the profile to that common plane, if possible.
+ * That makes the multi-segment bevels curve nicely in that plane, as users expect.
+ * The new midco should be either v (when neighbor edges are unbeveled)
+ * or the intersection of the offset lines (if they are).
* If the profile is going to lead into unbeveled edges on each side
* (that is, both BoundVerts are "on-edge" points on non-beveled edges)
- * then in order to get curve in multi-segment case, change projection plane
- * to be that common plane, projection dir to be the plane normal,
- * and mid to be the original vertex.
- * Otherwise, we just want to linearly interpolate between co1 and co2.
*/
- if (e->prev->is_bev || e->next->is_bev) {
+ if (DEBUG_OLD_PLANE_SPECIAL && (e->prev->is_bev || e->next->is_bev)) {
do_linear_interp = true;
}
else {
- copy_v3_v3(pro->coa, co1);
- copy_v3_v3(pro->midco, bv->v->co);
+ if (DEBUG_OLD_PROJ_TO_PERP_PLANE) {
+ copy_v3_v3(pro->coa, co1);
+ copy_v3_v3(pro->cob, co2);
+ }
+ if (DEBUG_OLD_FLAT_MID) {
+ copy_v3_v3(pro->midco, bv->v->co);
+ }
+ else {
+ copy_v3_v3(pro->midco, bv->v->co);
+ if (e->prev->is_bev && e->next->is_bev && bv->selcount >= 3) {
+ /* want mid at the meet point of next and prev offset edges */
+ float d3[3], d4[3], co4[3], meetco[3], isect2[3];
+ int isect_kind;
+
+ sub_v3_v3v3(d3, e->prev->e->v1->co, e->prev->e->v2->co);
+ sub_v3_v3v3(d4, e->next->e->v1->co, e->next->e->v2->co);
+ normalize_v3(d3);
+ normalize_v3(d4);
+ add_v3_v3v3(co3, co1, d3);
+ add_v3_v3v3(co4, co2, d4);
+ isect_kind = isect_line_line_v3(co1, co3, co2, co4, meetco, isect2);
+ if (isect_kind != 0) {
+ copy_v3_v3(pro->midco, meetco);
+ }
+ else {
+ /* offset lines are collinear - want linear interpolation */
+ mid_v3_v3v3(pro->midco, co1, co2);
+ do_linear_interp = true;
+ }
+ }
+ }
copy_v3_v3(pro->cob, co2);
sub_v3_v3v3(d1, pro->midco, co1);
normalize_v3(d1);
}
}
if (nsucs == 0 || (nsucs == 2 && j != 1) || nsucs > 2 ||
- (j == bv->edgecount - 1 && !edges_face_connected_at_vert(bmenext, bv->edges[0].e)))
+ (j == bv->edgecount - 1 && !edges_face_connected_at_vert(bmenext, bv->edges[0].e)))
{
for (k = 1; k < j; k++) {
BM_BEVEL_EDGE_TAG_DISABLE(bv->edges[k].e);
/* going cw */
if (vm->seg > 1) {
if (vm->mesh_kind == M_ADJ || bp->vertex_only ||
- (vm->mesh_kind == M_NONE && v->ebev != e && v->ebev != eprev))
+ (vm->mesh_kind == M_NONE && v->ebev != e && v->ebev != eprev))
{
i = v->prev->index;
for (k = vm->seg - 1; k > 0; k--) {
std::vector<COLLADAFW::Node *>::iterator it;
it = std::find(finished_joints.begin(), finished_joints.end(), node);
if (it != finished_joints.end()) return chain_length;
-
- // JointData* jd = get_joint_data(node);
- // TODO rename from Node "name" attrs later
EditBone *bone = ED_armature_edit_bone_add(arm, (char *)bc_get_joint_name(node));
totbone++;
- if (skin && skin->get_joint_inv_bind_matrix(joint_inv_bind_mat, node)) {
- // get original world-space matrix
- invert_m4_m4(mat, joint_inv_bind_mat);
+ /*
+ * We use the inv_bind_shape matrix to apply the armature bind pose as its rest pose.
+ */
+
+ std::map<COLLADAFW::UniqueId, SkinInfo>::iterator skin_it;
+ bool bone_is_not_skinned = true;
+ for (skin_it = skin_by_data_uid.begin(); skin_it != skin_by_data_uid.end(); skin_it++) {
+
+ SkinInfo *b = &skin_it->second;
+ if (b->get_joint_inv_bind_matrix(joint_inv_bind_mat, node)) {
- // And make local to armature
- Object *ob_arm = skin->BKE_armature_from_object();
- if (ob_arm) {
- float invmat[4][4];
- invert_m4_m4(invmat, ob_arm->obmat);
- mul_m4_m4m4(mat, invmat, mat);
+ // get original world-space matrix
+ invert_m4_m4(mat, joint_inv_bind_mat);
+
+ // And make local to armature
+ Object *ob_arm = skin->BKE_armature_from_object();
+ if (ob_arm) {
+ float invmat[4][4];
+ invert_m4_m4(invmat, ob_arm->obmat);
+ mul_m4_m4m4(mat, invmat, mat);
+ }
+
+ bone_is_not_skinned = false;
+ break;
}
}
+
// create a bone even if there's no joint data for it (i.e. it has no influence)
- else {
+ if (bone_is_not_skinned) {
float obmat[4][4];
// bone-space
get_node_mat(obmat, node, NULL, NULL);
float loc[3], size[3], rot[3][3];
- BoneExtended &be = add_bone_extended(bone, node, layer_labels);
+ BoneExtended &be = add_bone_extended(bone, node, totchild, layer_labels);
int layer = be.get_bone_layers();
if (layer) bone->layer = layer;
arm->layer |= layer; // ensure that all populated bone layers are visible after import
mat4_to_loc_rot_size(loc, rot, size, mat);
mat3_to_vec_roll(rot, NULL, &angle);
}
-
copy_v3_v3(bone->head, mat[3]);
add_v3_v3v3(bone->tail, bone->head, tail); //tail must be non zero
return armature_joints.back();
}
#endif
-void ArmatureImporter::create_armature_bones( )
+Object *ArmatureImporter::create_armature_bones(std::vector<Object *> &ob_arms)
{
std::vector<COLLADAFW::Node *>::iterator ri;
std::vector<std::string> layer_labels;
+ Object *ob_arm = NULL;
- leaf_bone_length = FLT_MAX;
//if there is an armature created for root_joint next root_joint
for (ri = root_joints.begin(); ri != root_joints.end(); ri++) {
if (get_armature_for_joint(*ri) != NULL) continue;
create_bone(NULL, *ri , NULL, (*ri)->getChildNodes().getCount(), NULL, armature, layer_labels);
/* exit armature edit mode to populate the Armature object */
+ unskinned_armature_map[(*ri)->getUniqueId()] = ob_arm;
ED_armature_from_edit(armature);
ED_armature_edit_free(armature);
- /* and step back to edit mode to fix the leaf nodes */
- ED_armature_to_edit(armature);
-
- if (this->import_settings->fix_orientation || this->import_settings->find_chains) {
-
- if (this->import_settings->find_chains)
- connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX);
-
- if (this->import_settings->fix_orientation)
- fix_leaf_bones(armature, (Bone *)armature->bonebase.first);
-
- // exit armature edit mode
- unskinned_armature_map[(*ri)->getUniqueId()] = ob_arm;
+ int index = std::find(ob_arms.begin(), ob_arms.end(), ob_arm) - ob_arms.begin();
+ if (index == 0) {
+ ob_arms.push_back(ob_arm);
}
- fix_parent_connect(armature, (Bone *)armature->bonebase.first);
-
- ED_armature_from_edit(armature);
- ED_armature_edit_free(armature);
-
DAG_id_tag_update(&ob_arm->id, OB_RECALC_OB | OB_RECALC_DATA);
}
+ return ob_arm;
}
-void ArmatureImporter::create_armature_bones(SkinInfo& skin)
+Object *ArmatureImporter::create_armature_bones(SkinInfo& skin)
{
// just do like so:
// - get armature
totbone = 0;
// bone_direction_row = 1; // TODO: don't default to Y but use asset and based on it decide on default row
- leaf_bone_length = FLT_MAX;
// create bones
/*
// since root_joints may contain joints for multiple controllers, we need to filter
if (skin.uses_joint_or_descendant(*ri)) {
+
create_bone(&skin, *ri, NULL, (*ri)->getChildNodes().getCount(), NULL, armature, layer_labels);
if (joint_parent_map.find((*ri)->getUniqueId()) != joint_parent_map.end() && !skin.get_parent())
ED_armature_from_edit(armature);
ED_armature_edit_free(armature);
- /* and step back to edit mode to fix the leaf nodes */
- ED_armature_to_edit(armature);
-
- if (armature->bonebase.first) {
- /* Do this only if Armature has bones */
- //connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX);
- //fix_leaf_bones(armature, (Bone *)armature->bonebase.first);
- }
- // exit armature edit mode
- ED_armature_from_edit(armature);
- ED_armature_edit_free(armature);
DAG_id_tag_update(&ob_arm->id, OB_RECALC_OB | OB_RECALC_DATA);
+
+ return ob_arm;
}
void ArmatureImporter::set_pose(Object *ob_arm, COLLADAFW::Node *root_node, const char *parentname, float parent_mat[4][4])
#endif
// here we add bones to armatures, having armatures previously created in write_controller
-void ArmatureImporter::make_armatures(bContext *C)
+void ArmatureImporter::make_armatures(bContext *C, std::vector<Object *> &objects_to_scale)
{
+ std::vector<Object *> ob_arms;
std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
+
+ leaf_bone_length = FLT_MAX; /*TODO: Make this work for more than one armature in the import file*/
+
for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
SkinInfo& skin = it->second;
- create_armature_bones(skin);
+ Object *ob_arm = create_armature_bones(skin);
// link armature with a mesh object
const COLLADAFW::UniqueId &uid = skin.get_controller_uid();
const COLLADAFW::UniqueId *guid = get_geometry_uid(uid);
if (guid != NULL) {
Object *ob = mesh_importer->get_object_by_geom_uid(*guid);
- if (ob)
+ if (ob) {
skin.link_armature(C, ob, joint_by_uid, this);
+
+ std::vector<Object *>::iterator ob_it = std::find(objects_to_scale.begin(), objects_to_scale.end(), ob);
+
+ if (ob_it != objects_to_scale.end()) {
+ int index = ob_it - objects_to_scale.begin();
+ objects_to_scale.erase(objects_to_scale.begin() + index);
+ }
+
+ if (std::find(objects_to_scale.begin(), objects_to_scale.end(), ob_arm) == objects_to_scale.end()) {
+ objects_to_scale.push_back(ob_arm);
+ }
+
+ if (std::find(ob_arms.begin(), ob_arms.end(), ob_arm) == ob_arms.end()) {
+ ob_arms.push_back(ob_arm);
+ }
+ }
else
fprintf(stderr, "Cannot find object to link armature with.\n");
}
}
//for bones without skins
- create_armature_bones();
+ create_armature_bones(ob_arms);
+
+ // Fix bone relations
+ std::vector<Object *>::iterator ob_arm_it;
+ for (ob_arm_it = ob_arms.begin(); ob_arm_it != ob_arms.end(); ob_arm_it++) {
+
+ Object *ob_arm = *ob_arm_it;
+ bArmature *armature = (bArmature *)ob_arm->data;
+
+ /* and step back to edit mode to fix the leaf nodes */
+ ED_armature_to_edit(armature);
+
+ if (this->import_settings->fix_orientation || this->import_settings->find_chains) {
+
+ if (this->import_settings->find_chains)
+ connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX);
+
+ if (this->import_settings->fix_orientation)
+ fix_leaf_bones(armature, (Bone *)armature->bonebase.first);
+
+ // exit armature edit mode
+
+ }
+
+ fix_parent_connect(armature, (Bone *)armature->bonebase.first);
+
+ ED_armature_from_edit(armature);
+ ED_armature_edit_free(armature);
+ }
}
#if 0
return found;
}
-BoneExtended &ArmatureImporter::add_bone_extended(EditBone *bone, COLLADAFW::Node *node, std::vector<std::string> &layer_labels)
+BoneExtended &ArmatureImporter::add_bone_extended(EditBone *bone, COLLADAFW::Node *node, int sibcount, std::vector<std::string> &layer_labels)
{
BoneExtended *be = new BoneExtended(bone);
extended_bones[bone->name] = be;
TagsMap::iterator etit;
ExtraTags *et = 0;
etit = uid_tags_map.find(node->getUniqueId().toAscii());
+
+ bool has_connect = false;
+ int connect_type = -1;
+
if (etit != uid_tags_map.end()) {
float tail[3] = { FLT_MAX, FLT_MAX, FLT_MAX };
float roll = 0;
- int use_connect = -1;
std::string layers;
et = etit->second;
has_tail |= et->setData("tip_y", &tail[1]);
has_tail |= et->setData("tip_z", &tail[2]);
- bool has_connect = et->setData("connect", &use_connect);
- bool has_roll = et->setData("roll", &roll);
+ has_connect = et->setData("connect", &connect_type);
+ bool has_roll = et->setData("roll", &roll);
layers = et->setData("layer", layers);
if (has_tail && !has_connect)
{
- use_connect = 0; // got a bone tail definition but no connect info -> bone is not connected
+ /* got a bone tail definition but no connect info -> bone is not connected */
+ has_connect = true;
+ connect_type = 0;
}
be->set_bone_layers(layers, layer_labels);
if (has_tail) be->set_tail(tail);
if (has_roll) be->set_roll(roll);
- be->set_use_connect(use_connect);
}
+
+ if (!has_connect && this->import_settings->auto_connect) {
+ /* auto connect only whyen parent has exactly one child*/
+ connect_type = sibcount == 1;
+ }
+
+ be->set_use_connect(connect_type);
be->set_leaf_bone(true);
return *be;
int create_bone(SkinInfo* skin, COLLADAFW::Node *node, EditBone *parent, int totchild,
float parent_mat[4][4], bArmature *arm, std::vector<std::string> &layer_labels);
- BoneExtended &add_bone_extended(EditBone *bone, COLLADAFW::Node * node, std::vector<std::string> &layer_labels);
+ BoneExtended &add_bone_extended(EditBone *bone, COLLADAFW::Node * node, int sibcount, std::vector<std::string> &layer_labels);
void clear_extended_boneset();
void fix_leaf_bones(bArmature *armature, Bone *bone);
ArmatureJoints& get_armature_joints(Object *ob_arm);
#endif
- void create_armature_bones(SkinInfo& skin);
- void create_armature_bones( );
+ Object *create_armature_bones(SkinInfo& skin);
+ Object *create_armature_bones(std::vector<Object *> &arm_objs);
/** TagsMap typedef for uid_tags_map. */
typedef std::map<std::string, ExtraTags*> TagsMap;
void add_root_joint(COLLADAFW::Node *node, Object *parent);
// here we add bones to armatures, having armatures previously created in write_controller
- void make_armatures(bContext *C);
+ void make_armatures(bContext *C, std::vector<Object *> &objects_to_scale);
void make_shape_keys();
mesh_importer.optimize_material_assignements();
armature_importer.set_tags_map(this->uid_tags_map);
- armature_importer.make_armatures(mContext);
+ armature_importer.make_armatures(mContext, *objects_to_scale);
armature_importer.make_shape_keys();
DAG_relations_tag_update(bmain);
name.c_str());
if (is_joint) {
- if (parent_node == NULL) {
+ if (parent_node == NULL && !is_library_node) {
// A Joint on root level is a skeleton without root node.
// Here we add the armature "on the fly":
par = bc_add_object(sce, OB_ARMATURE, std::string("Armature").c_str());
public:
bool import_units;
bool find_chains;
+ bool auto_connect;
bool fix_orientation;
int min_chain_length;
char *filepath;
MeshImporter::MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce) : unitconverter(unitconv), scene(sce), armature_importer(arm) {
}
-void MeshImporter::set_poly_indices(MPoly *mpoly, MLoop *mloop, int loop_index, unsigned int *indices, int loop_count)
+bool MeshImporter::set_poly_indices(MPoly *mpoly, MLoop *mloop, int loop_index, unsigned int *indices, int loop_count)
{
mpoly->loopstart = loop_index;
mpoly->totloop = loop_count;
-
+ bool broken_loop = false;
for (int index=0; index < loop_count; index++) {
+
+ /* Test if loop defines a hole */
+ if (!broken_loop) {
+ for (int i = 0; i < index; i++) {
+ if (indices[i] == indices[index]) {
+ // duplicate index -> not good
+ broken_loop = true;
+ }
+ }
+ }
+
mloop->v = indices[index];
mloop++;
}
+ return broken_loop;
}
void MeshImporter::set_vcol(MLoopCol *mlc, VCOLDataWrapper &vob, int loop_index, COLLADAFW::IndexList &index_list, int count)
COLLADAFW::IndexListArray& index_list_array_uvcoord = mp->getUVCoordIndicesArray();
COLLADAFW::IndexListArray& index_list_array_vcolor = mp->getColorIndicesArray();
+ int invalid_loop_holes = 0;
for (unsigned int j = 0; j < prim_totpoly; j++) {
// Vertices in polygon:
if (vcount < 0) {
continue; // TODO: add support for holes
}
- set_poly_indices(mpoly, mloop, loop_index, position_indices, vcount);
+ bool broken_loop = set_poly_indices(mpoly, mloop, loop_index, position_indices, vcount);
+ if (broken_loop)
+ {
+ invalid_loop_holes += 1;
+ }
for (unsigned int uvset_index = 0; uvset_index < index_list_array_uvcoord.getCount(); uvset_index++) {
// get mtface by face index and uv set index
position_indices += vcount;
}
+
+ if (invalid_loop_holes > 0)
+ {
+ fprintf(stderr, "Collada import: Mesh [%s] : contains %d unsupported loops (holes).\n", me->id.name, invalid_loop_holes);
+ }
}
else if (collada_meshtype == COLLADAFW::MeshPrimitive::LINES) {
std::map<COLLADAFW::UniqueId, MaterialIdPrimitiveArrayMap> geom_uid_mat_mapping_map; // crazy name!
std::multimap<COLLADAFW::UniqueId, COLLADAFW::UniqueId> materials_mapped_to_geom; //< materials that have already been mapped to a geometry. A pair of geom uid and mat uid, one geometry can have several materials
- void set_poly_indices(MPoly *mpoly,
+ bool set_poly_indices(MPoly *mpoly,
MLoop *mloop,
int loop_index,
unsigned int *indices,
ModifierData *md = ED_object_modifier_add(NULL, bmain, scene, ob, NULL, eModifierType_Armature);
ArmatureModifierData *amd = (ArmatureModifierData *)md;
amd->object = ob_arm;
+ struct bArmature *armature = (bArmature *)ob_arm->data;
#if 1
bc_set_parent(ob, ob_arm, C);
const char *filepath,
int import_units,
int find_chains,
+ int auto_connect,
int fix_orientation,
int min_chain_length)
{
ImportSettings import_settings;
import_settings.filepath = (char *)filepath;
import_settings.import_units = import_units != 0;
+ import_settings.auto_connect = auto_connect != 0;
import_settings.find_chains = find_chains != 0;
import_settings.fix_orientation = fix_orientation != 0;
import_settings.min_chain_length = min_chain_length;
const char *filepath,
int import_units,
int find_chains,
+ int auto_connect,
int fix_orientation,
int min_chain_length);
float roll;
int bone_layers;
- bool use_connect;
+ int use_connect;
bool has_custom_tail;
bool has_custom_roll;
for (Base *base = (Base *)scene->base.first; base; base = base->next) {
Object *ob = base->object;
- /* object itself */
- build_object(scene, base, ob);
-
/* object that this is a proxy for */
// XXX: the way that proxies work needs to be completely reviewed!
if (ob->proxy) {
ob->proxy->proxy_from = ob;
- build_object(scene, base, ob->proxy);
}
+ /* object itself */
+ build_object(scene, base, ob);
+
/* Object dupligroup. */
if (ob->dup_group) {
build_group(scene, base, ob->dup_group);
if (ob->gpd) {
build_gpencil(ob->gpd);
}
+
+ if (ob->proxy != NULL) {
+ add_operation_node(&ob->id, DEPSNODE_TYPE_PROXY, DEPSOP_TYPE_POST,
+ function_bind(BKE_object_eval_proxy_backlink, _1, ob),
+ DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
+ }
}
void DepsgraphNodeBuilder::build_object_transform(Scene *scene, Object *ob)
for (Base *base = (Base *)scene->base.first; base; base = base->next) {
Object *ob = base->object;
+ /* Object that this is a proxy for.
+ * Just makes sure backlink is correct.
+ */
+ if (ob->proxy) {
+ ob->proxy->proxy_from = ob;
+ }
+
/* object itself */
build_object(bmain, scene, ob);
break;
}
-
case OB_ARMATURE: /* Pose */
if (ob->id.lib != NULL && ob->proxy_from != NULL) {
build_proxy_rig(ob);
id_node->done = 0;
node->scheduled = false;
node->owner->flags &= ~DEPSCOMP_FULLY_SCHEDULED;
+ if (node->owner->type == DEPSNODE_TYPE_PROXY) {
+ node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+ }
}
/* Flush updates from tagged nodes outwards until all affected nodes
"Create drivers for each pair of corresponding elements"},
{CREATEDRIVER_MAPPING_NONE_ALL, "NONE_ALL", ICON_HAND, "Manually Create Later",
- "Create drivers for all properites without assigning any targets yet"},
+ "Create drivers for all properties without assigning any targets yet"},
{CREATEDRIVER_MAPPING_NONE, "NONE_SINGLE", 0, "Manually Create Later (Single)",
"Create driver for this property only and without assigning any targets yet"},
{0, NULL, 0, NULL, NULL}
if (ts->snap_mode == SCE_SNAP_MODE_VOLUME) {
float size;
if (peelObjectsSnapContext(
- snap_context, mvalf, SNAP_ALL,
+ snap_context, mvalf,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_NOT_SELECTED,
+ .use_object_edit_cage = false,
+ },
(ts->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0,
loc, dummy_no, &size))
{
{
if (ED_transform_snap_object_project_view3d(
snap_context,
+ ts->snap_mode,
&(const struct SnapObjectParams){
.snap_select = SNAP_NOT_SELECTED,
- .snap_to = ts->snap_mode,
+ .use_object_edit_cage = false,
},
mvalf, &dist_px, NULL,
loc, dummy_no))
ED_transform_snap_object_project_view3d_mixed(
snap_context,
+ SCE_SELECT_FACE,
&(const struct SnapObjectParams){
- .snap_select = SNAP_NOT_OBEDIT,
- .snap_to_flag = SCE_SELECT_FACE,
+ .snap_select = (vc.scene->obedit != NULL) ? SNAP_NOT_ACTIVE : SNAP_ALL,
+ .use_object_edit_cage = false,
},
mval, NULL, true,
location, NULL);
struct Object;
/* rigidbody_object.c */
-bool ED_rigidbody_object_add(struct Scene *scene, struct Object *ob, int type, struct ReportList *reports);
-void ED_rigidbody_object_remove(struct Scene *scene, struct Object *ob);
+bool ED_rigidbody_object_add(struct Main *bmain, struct Scene *scene, struct Object *ob, int type, struct ReportList *reports);
+void ED_rigidbody_object_remove(struct Main *bmain, struct Scene *scene, struct Object *ob);
/* rigidbody_constraint.c */
-bool ED_rigidbody_constraint_add(struct Scene *scene, struct Object *ob, int type, struct ReportList *reports);
-void ED_rigidbody_constraint_remove(struct Scene *scene, struct Object *ob);
+bool ED_rigidbody_constraint_add(struct Main *bmain, struct Scene *scene, struct Object *ob, int type, struct ReportList *reports);
+void ED_rigidbody_constraint_remove(struct Main *bmain, struct Scene *scene, struct Object *ob);
/* operators */
void ED_operatortypes_physics(void);
int sfra; /* frame that playback was started from */
int nextfra; /* next frame to go to (when ANIMPLAY_FLAG_USE_NEXT_FRAME is set) */
double last_duration; /* used for frame dropping */
+ bool from_anim_edit; /* playback was invoked from animation editor */
} ScreenAnimData;
/* for animplayer */
struct wmOperatorType;
struct Main;
struct SnapObjectContext;
+struct SnapObjectParams;
void transform_keymap_for_space(struct wmKeyConfig *keyconf, struct wmKeyMap *keymap, int spaceid);
void transform_operatortypes(void);
typedef enum SnapSelect {
SNAP_ALL = 0,
SNAP_NOT_SELECTED = 1,
- SNAP_NOT_OBEDIT = 2
+ SNAP_NOT_ACTIVE = 2,
} SnapSelect;
#define SNAP_MIN_DISTANCE 30
bool peelObjectsTransform(
- struct TransInfo *t, const float mval[2],
- SnapSelect snap_select, bool use_peel_object,
+ struct TransInfo *t,
+ const float mval[2],
+ const bool use_peel_object,
/* return args */
float r_loc[3], float r_no[3], float *r_thickness);
bool peelObjectsSnapContext(
struct SnapObjectContext *sctx,
const float mval[2],
- SnapSelect snap_select, bool use_peel_object,
+ const struct SnapObjectParams *params,
+ const bool use_peel_object,
/* return args */
float r_loc[3], float r_no[3], float *r_thickness);
bool snapObjectsTransform(
- struct TransInfo *t, const float mval[2], SnapSelect snap_select,
+ struct TransInfo *t, const float mval[2],
float *dist_px,
/* return args */
float r_loc[3], float r_no[3]);
unsigned int ob_uuid;
};
+/** parameters that define which objects will be used to snap. */
struct SnapObjectParams {
- int snap_select; /* SnapSelect */
- union {
- unsigned int snap_to : 4;
- /* snap_target_flag: Snap to vert/edge/face. */
- unsigned int snap_to_flag : 4;
- };
+ /* special context sensitive handling for the active or selected object */
+ char snap_select;
/* use editmode cage */
- unsigned int use_object_edit : 1;
- /* special context sensitive handling for the active object */
- unsigned int use_object_active : 1;
+ unsigned int use_object_edit_cage : 1;
};
enum {
bool ED_transform_snap_object_project_ray_ex(
struct SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3], float *ray_depth,
/* return args */
struct Object **r_ob, float r_obmat[4][4]);
bool ED_transform_snap_object_project_ray(
SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
const float ray_origin[3], const float ray_direction[3], float *ray_depth,
float r_co[3], float r_no[3]);
bool ED_transform_snap_object_project_ray_all(
SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3],
float ray_depth, bool sort,
bool ED_transform_snap_object_project_view3d_ex(
struct SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float mval[2], float *dist_px,
float *ray_depth,
float r_loc[3], float r_no[3], int *r_index);
bool ED_transform_snap_object_project_view3d(
struct SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float mval[2], float *dist_px,
float *ray_depth,
float r_loc[3], float r_no[3]);
bool ED_transform_snap_object_project_view3d_mixed(
SnapObjectContext *sctx,
+ const unsigned short snap_to_flag,
const struct SnapObjectParams *params,
const float mval_fl[2], float *dist_px,
bool use_depth,
return ptr;
}
+/**
+ * Check if a #uiAfterFunc is needed for this button.
+ */
+static bool ui_afterfunc_check(const uiBlock *block, const uiBut *but)
+{
+ return (but->func || but->funcN || but->rename_func || but->optype || but->rnaprop || block->handle_func ||
+ (but->type == UI_BTYPE_BUT_MENU && block->butm_func));
+}
+
static void ui_apply_but_func(bContext *C, uiBut *but)
{
uiAfterFunc *after;
* handling is done, i.e. menus are closed, in order to avoid conflicts
* with these functions removing the buttons we are working with */
- if (but->func || but->funcN || block->handle_func || but->rename_func ||
- (but->type == UI_BTYPE_BUT_MENU && block->butm_func) || but->optype || but->rnaprop)
- {
+ if (ui_afterfunc_check(block, but)) {
after = ui_afterfunc_new();
if (but->func && ELEM(but, but->func_arg1, but->func_arg2)) {
* having typed something already. */
but->rename_orig = BLI_strdup(data->origstr);
}
- else {
+ /* only if there are afterfuncs, otherwise 'renam_orig' isn't freed */
+ else if (ui_afterfunc_check(but->block, but)) {
but->rename_orig = data->origstr;
data->origstr = NULL;
}
}
ot = WM_operatortype_find(EDTSRC_I18N_OP_NAME, 0);
if (ot == NULL) {
- BKE_reportf(op->reports, RPT_ERROR, "Could not find operator '%s'! Please enable ui_translate addon "
+ BKE_reportf(op->reports, RPT_ERROR, "Could not find operator '%s'! Please enable ui_translate add-on "
"in the User Preferences", EDTSRC_I18N_OP_NAME);
return OPERATOR_CANCELLED;
}
char filename[FILE_MAX];
int import_units;
int find_chains;
+ int auto_connect;
int fix_orientation;
int min_chain_length;
/* Options panel */
import_units = RNA_boolean_get(op->ptr, "import_units");
find_chains = RNA_boolean_get(op->ptr, "find_chains");
+ auto_connect = RNA_boolean_get(op->ptr, "auto_connect");
fix_orientation = RNA_boolean_get(op->ptr, "fix_orientation");
min_chain_length = RNA_int_get(op->ptr, "min_chain_length");
C, filename,
import_units,
find_chains,
+ auto_connect,
fix_orientation,
min_chain_length))
{
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "find_chains", 0, NULL, ICON_NONE);
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "auto_connect", 0, NULL, ICON_NONE);
+
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "min_chain_length", 0, NULL, ICON_NONE);
}
"find_chains", 0, "Find Bone Chains",
"Find best matching Bone Chains and ensure bones in chain are connected");
+ RNA_def_boolean(ot->srna,
+ "auto_connect", 0, "Auto Connect",
+ "set use_connect for parent bones which have exactly one child bone");
+
RNA_def_int(ot->srna,
"min_chain_length",
0,
#define MVAL_PIXEL_MARGIN 5.0f
+/* until implement profile = 0 case, need to clamp somewhat above zero */
+#define PROFILE_HARD_MIN 0.15f
+
typedef struct {
BMEditMesh *em;
float initial_length;
BMBackup mesh_backup;
void *draw_handle_pixel;
short twtype;
+ bool mouse_controls_profile;
float segments; /* Segments as float so smooth mouse pan works in small increments */
} BevelData;
static void edbm_bevel_update_header(bContext *C, wmOperator *op)
{
const char *str = IFACE_("Confirm: (Enter/LMB), Cancel: (Esc/RMB), Mode: %s (M), Clamp Overlap: %s (C), "
- "Vertex Only: %s (V), Offset: %s, Segments: %d");
+ "Vertex Only: %s (V), Profile Control: %s (P), Offset: %s, Segments: %d");
char msg[UI_MAX_DRAW_STR];
ScrArea *sa = CTX_wm_area(C);
BLI_snprintf(msg, sizeof(msg), str, type_str,
WM_bool_as_string(RNA_boolean_get(op->ptr, "clamp_overlap")),
WM_bool_as_string(RNA_boolean_get(op->ptr, "vertex_only")),
+ WM_bool_as_string(opdata->mouse_controls_profile),
offset_str, RNA_int_get(op->ptr, "segments"));
ED_area_headerprint(sa, msg);
opdata->em = em;
opdata->is_modal = is_modal;
opdata->shift_factor = -1.0f;
+ opdata->mouse_controls_profile = false;
initNumInput(&opdata->num_input);
opdata->num_input.idx_max = 0;
{
BevelData *opdata = op->customdata;
bool use_dist;
- bool is_percent;
+ bool is_percent, is_profile;
float mdiff[2];
float factor;
mdiff[1] = opdata->mcenter[1] - event->mval[1];
is_percent = (RNA_enum_get(op->ptr, "offset_type") == BEVEL_AMT_PERCENT);
use_dist = !is_percent;
+ is_profile = opdata->mouse_controls_profile;
factor = ((len_v2(mdiff) - MVAL_PIXEL_MARGIN) - opdata->initial_length) * opdata->pixel_size;
/* Fake shift-transform... */
if (event->shift) {
if (opdata->shift_factor < 0.0f) {
- opdata->shift_factor = RNA_float_get(op->ptr, "offset");
- if (is_percent) {
- opdata->shift_factor /= 100.0f;
+ if (is_profile)
+ opdata->shift_factor = RNA_float_get(op->ptr, "profile");
+ else {
+ opdata->shift_factor = RNA_float_get(op->ptr, "offset");
+ if (is_percent) {
+ opdata->shift_factor /= 100.0f;
+ }
}
}
factor = (factor - opdata->shift_factor) * 0.1f + opdata->shift_factor;
opdata->shift_factor = -1.0f;
}
- /* clamp differently based on distance/factor */
- if (use_dist) {
- if (factor < 0.0f) factor = 0.0f;
+ /* clamp differently based on distance/factor/profile */
+ if (is_profile) {
+ CLAMP(factor, PROFILE_HARD_MIN, 1.0f);
}
else {
- CLAMP(factor, 0.0f, 1.0f);
- if (is_percent) {
- factor *= 100.0f;
+ if (use_dist) {
+ if (factor < 0.0f) factor = 0.0f;
+ }
+ else {
+ CLAMP(factor, 0.0f, 1.0f);
+ if (is_percent) {
+ factor *= 100.0f;
+ }
}
}
case MOUSEMOVE:
if (!has_numinput) {
const float factor = edbm_bevel_mval_factor(op, event);
- RNA_float_set(op->ptr, "offset", factor);
+ if (opdata->mouse_controls_profile)
+ RNA_float_set(op->ptr, "profile", factor);
+ else
+ RNA_float_set(op->ptr, "offset", factor);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
edbm_bevel_update_header(C, op);
handled = true;
break;
+ case PKEY:
+ if (event->val == KM_RELEASE)
+ break;
+ opdata->mouse_controls_profile = !opdata->mouse_controls_profile;
+ break;
case VKEY:
if (event->val == KM_RELEASE)
break;
prop = RNA_def_float(ot->srna, "offset", 0.0f, -1e6f, 1e6f, "Amount", "", 0.0f, 1.0f);
RNA_def_property_float_array_funcs_runtime(prop, NULL, NULL, mesh_ot_bevel_offset_range_func);
RNA_def_int(ot->srna, "segments", 1, 1, 50, "Segments", "Segments for curved edge", 1, 8);
- RNA_def_float(ot->srna, "profile", 0.5f, 0.15f, 1.0f, "Profile", "Controls profile shape (0.5 = round)", 0.15f, 1.0f);
+ RNA_def_float(ot->srna, "profile", 0.5f, PROFILE_HARD_MIN, 1.0f, "Profile",
+ "Controls profile shape (0.5 = round)", PROFILE_HARD_MIN, 1.0f);
RNA_def_boolean(ot->srna, "vertex_only", false, "Vertex Only", "Bevel only vertices");
RNA_def_boolean(ot->srna, "clamp_overlap", false, "Clamp Overlap",
"Do not allow beveled edges/vertices to overlap each other");
if (ED_view3d_project_float_object(ar, eve->co, mval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
if (ED_transform_snap_object_project_view3d_mixed(
snap_context,
+ SCE_SELECT_FACE,
&(const struct SnapObjectParams){
- .snap_select = SNAP_NOT_OBEDIT,
- .snap_to_flag = SCE_SELECT_FACE,
+ .snap_select = SNAP_NOT_ACTIVE,
+ .use_object_edit_cage = false,
},
mval, NULL, true,
co_proj, NULL))
if (newob->type == OB_CURVE) {
BKE_object_free_modifiers(newob); /* after derivedmesh calls! */
- ED_rigidbody_object_remove(scene, newob);
+ ED_rigidbody_object_remove(bmain, scene, newob);
}
}
else if (ob->type == OB_MESH && ob->modifiers.first) { /* converting a mesh with no modifiers causes a segfault */
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_group.h"
+#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_rigidbody.h"
}
-bool ED_rigidbody_constraint_add(Scene *scene, Object *ob, int type, ReportList *reports)
+bool ED_rigidbody_constraint_add(Main *bmain, Scene *scene, Object *ob, int type, ReportList *reports)
{
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
}
/* create constraint group if it doesn't already exits */
if (rbw->constraints == NULL) {
- rbw->constraints = BKE_group_add(G.main, "RigidBodyConstraints");
+ rbw->constraints = BKE_group_add(bmain, "RigidBodyConstraints");
}
/* make rigidbody constraint settings */
ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, type);
/* add constraint to rigid body constraint group */
BKE_group_object_add(rbw->constraints, ob, scene, NULL);
+ DAG_relations_tag_update(bmain);
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
return true;
}
-void ED_rigidbody_constraint_remove(Scene *scene, Object *ob)
+void ED_rigidbody_constraint_remove(Main *bmain, Scene *scene, Object *ob)
{
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
if (rbw)
BKE_group_object_unlink(rbw->constraints, ob, scene, NULL);
+ DAG_relations_tag_update(bmain);
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
}
static int rigidbody_con_add_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
Object *ob = (scene) ? OBACT : NULL;
return OPERATOR_CANCELLED;
}
/* apply to active object */
- changed = ED_rigidbody_constraint_add(scene, ob, type, op->reports);
+ changed = ED_rigidbody_constraint_add(bmain, scene, ob, type, op->reports);
if (changed) {
/* send updates */
static int rigidbody_con_remove_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = (scene) ? OBACT : NULL;
return OPERATOR_CANCELLED;
}
else {
- ED_rigidbody_constraint_remove(scene, ob);
+ ED_rigidbody_constraint_remove(bmain, scene, ob);
}
/* send updates */
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_group.h"
+#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_rigidbody.h"
/* ----------------- */
-bool ED_rigidbody_object_add(Scene *scene, Object *ob, int type, ReportList *reports)
+bool ED_rigidbody_object_add(Main *bmain, Scene *scene, Object *ob, int type, ReportList *reports)
{
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
scene->rigidbody_world = rbw;
}
if (rbw->group == NULL) {
- rbw->group = BKE_group_add(G.main, "RigidBodyWorld");
+ rbw->group = BKE_group_add(bmain, "RigidBodyWorld");
}
/* make rigidbody object settings */
/* add object to rigid body group */
BKE_group_object_add(rbw->group, ob, scene, NULL);
+ DAG_relations_tag_update(bmain);
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
return true;
}
-void ED_rigidbody_object_remove(Scene *scene, Object *ob)
+void ED_rigidbody_object_remove(Main *bmain, Scene *scene, Object *ob)
{
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
if (rbw)
BKE_group_object_unlink(rbw->group, ob, scene, NULL);
+ DAG_relations_tag_update(bmain);
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
}
static int rigidbody_object_add_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
int type = RNA_enum_get(op->ptr, "type");
bool changed;
/* apply to active object */
- changed = ED_rigidbody_object_add(scene, ob, type, op->reports);
+ changed = ED_rigidbody_object_add(bmain, scene, ob, type, op->reports);
if (changed) {
/* send updates */
static int rigidbody_object_remove_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
bool changed = false;
/* apply to active object */
if (!ELEM(NULL, ob, ob->rigidbody_object)) {
- ED_rigidbody_object_remove(scene, ob);
+ ED_rigidbody_object_remove(bmain, scene, ob);
changed = true;
}
static int rigidbody_objects_add_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
int type = RNA_enum_get(op->ptr, "type");
bool changed = false;
/* create rigid body objects and add them to the world's group */
CTX_DATA_BEGIN(C, Object *, ob, selected_objects) {
- changed |= ED_rigidbody_object_add(scene, ob, type, op->reports);
+ changed |= ED_rigidbody_object_add(bmain, scene, ob, type, op->reports);
}
CTX_DATA_END;
static int rigidbody_objects_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
bool changed = false;
CTX_DATA_BEGIN(C, Object *, ob, selected_objects)
{
if (ob->rigidbody_object) {
- ED_rigidbody_object_remove(scene, ob);
+ ED_rigidbody_object_remove(bmain, scene, ob);
changed = true;
}
}
sad->refresh = refresh;
sad->flag |= (enable < 0) ? ANIMPLAY_FLAG_REVERSE : 0;
sad->flag |= (sync == 0) ? ANIMPLAY_FLAG_NO_SYNC : (sync == 1) ? ANIMPLAY_FLAG_SYNC : 0;
-
+
+ ScrArea *sa = CTX_wm_area(C);
+ sad->from_anim_edit = (ELEM(sa->spacetype, SPACE_IPO, SPACE_ACTION, SPACE_NLA, SPACE_TIME));
+
screen->animtimer->customdata = sad;
}
return 0;
}
-static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
+static int match_region_with_redraws(int spacetype, int regiontype, int redraws, bool from_anim_edit)
{
if (regiontype == RGN_TYPE_WINDOW) {
switch (spacetype) {
case SPACE_VIEW3D:
- if (redraws & TIME_ALL_3D_WIN)
+ if ((redraws & TIME_ALL_3D_WIN) || from_anim_edit)
return 1;
break;
case SPACE_IPO:
case SPACE_ACTION:
case SPACE_NLA:
- if (redraws & TIME_ALL_ANIM_WIN)
+ if ((redraws & TIME_ALL_ANIM_WIN) || from_anim_edit)
return 1;
break;
case SPACE_TIME:
/* if only 1 window or 3d windows, we do timeline too */
- if (redraws & (TIME_ALL_ANIM_WIN | TIME_REGION | TIME_ALL_3D_WIN))
+ if ((redraws & (TIME_ALL_ANIM_WIN | TIME_REGION | TIME_ALL_3D_WIN)) || from_anim_edit)
return 1;
break;
case SPACE_BUTS:
return 1;
break;
case SPACE_SEQ:
- if (redraws & (TIME_SEQ | TIME_ALL_ANIM_WIN))
+ if ((redraws & (TIME_SEQ | TIME_ALL_ANIM_WIN)) || from_anim_edit)
return 1;
break;
case SPACE_NODE:
return 1;
break;
case SPACE_IMAGE:
- if (redraws & TIME_ALL_IMAGE_WIN)
+ if ((redraws & TIME_ALL_IMAGE_WIN) || from_anim_edit)
return 1;
break;
case SPACE_CLIP:
- if (redraws & TIME_CLIPS)
+ if ((redraws & TIME_CLIPS) || from_anim_edit)
return 1;
break;
if (ar == sad->ar) {
redraw = true;
}
- else if (match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws)) {
+ else if (match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws, sad->from_anim_edit)) {
redraw = true;
}
translation[1] = y;
outline_alpha = 0.5;
outline_col = brush->add_col;
- final_radius = BKE_brush_size_get(scene, brush) * zoomx;
+ final_radius = (BKE_brush_size_get(scene, brush) * zoomx) / U.pixelsize;
/* don't calculate rake angles while a stroke is active because the rake variables are global and
* we may get interference with the stroke itself. For line strokes, such interference is visible */
* so it's easier for now to just read the F-Curve directly.
* (TODO: add the full-blown PointerRNA relative parsing case here...)
*/
- if (ale->id && !ale->owner)
+ if (ale->id && !ale->owner) {
insert_keyframe(reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, flag);
- else
- insert_vert_fcurve(fcu, cfra, fcu->curval, ts->keyframe_type, 0);
+ }
+ else {
+ const float curval = evaluate_fcurve(fcu, cfra);
+ insert_vert_fcurve(fcu, cfra, curval, ts->keyframe_type, 0);
+ }
ale->update |= ANIM_UPDATE_DEFAULT;
}
* - fcu->driver != NULL: If this is set, then it's a driver. If we don't check for this, we'd end
* up adding the keyframes on a new F-Curve in the action data instead.
*/
- if (ale->id && !ale->owner && !fcu->driver)
+ if (ale->id && !ale->owner && !fcu->driver) {
insert_keyframe(reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, flag);
- else
- insert_vert_fcurve(fcu, cfra, fcu->curval, ts->keyframe_type, 0);
+ }
+ else {
+ const float curval = evaluate_fcurve(fcu, cfra);
+ insert_vert_fcurve(fcu, cfra, curval, ts->keyframe_type, 0);
+ }
ale->update |= ANIM_UPDATE_DEFAULT;
}
if (scene->r.mode & R_BORDER) {
float x3, y3, x4, y4;
- x3 = x1i + 1 + roundf(scene->r.border.xmin * (x2 - x1));
- y3 = y1i + 1 + roundf(scene->r.border.ymin * (y2 - y1));
- x4 = x1i + 1 + roundf(scene->r.border.xmax * (x2 - x1));
- y4 = y1i + 1 + roundf(scene->r.border.ymax * (y2 - y1));
+ x3 = floorf(x1 + (scene->r.border.xmin * (x2 - x1))) - 1;
+ y3 = floorf(y1 + (scene->r.border.ymin * (y2 - y1))) - 1;
+ x4 = floorf(x1 + (scene->r.border.xmax * (x2 - x1))) + (U.pixelsize - 1);
+ y4 = floorf(y1 + (scene->r.border.ymax * (y2 - y1))) + (U.pixelsize - 1);
cpack(0x4040FF);
sdrawbox(x3, y3, x4, y4);
if (ED_transform_snap_object_project_view3d_mixed(
ruler_info->snap_context,
+ SCE_SELECT_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
- .snap_to_flag = SCE_SELECT_FACE,
+ .use_object_edit_cage = true,
},
mval_fl, &dist_px, true,
co, ray_normal))
madd_v3_v3v3fl(ray_start, co, ray_normal, eps_bias);
ED_transform_snap_object_project_ray(
ruler_info->snap_context,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ .use_object_edit_cage = true,
+ },
ray_start, ray_normal, NULL,
co_other, NULL);
}
if (ED_transform_snap_object_project_view3d_mixed(
ruler_info->snap_context,
+ (SCE_SELECT_VERTEX | SCE_SELECT_EDGE) | (use_depth ? SCE_SELECT_FACE : 0),
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
- .snap_to_flag = (SCE_SELECT_VERTEX | SCE_SELECT_EDGE) | (use_depth ? SCE_SELECT_FACE : 0),
+ .use_object_edit_cage = true,
},
mval_fl, &dist_px, use_depth,
co, NULL))
#include "ED_screen.h"
#include "ED_space_api.h"
+#include "ED_transform.h"
#include "ED_transform_snap_object_context.h"
#include "PIL_time.h" /* smoothview */
ret = ED_transform_snap_object_project_ray(
walk->snap_context,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ },
ray_start, ray_normal, r_distance,
r_location, r_normal_dummy);
ret = ED_transform_snap_object_project_ray(
walk->snap_context,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ },
ray_start, ray_normal, NULL,
r_location, r_normal);
if (ED_view3d_project_float_global(t->ar, iloc, mval_fl, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
if (snapObjectsTransform(
- t, mval_fl, t->tsnap.modeSelect, &dist_px,
+ t, mval_fl, &dist_px,
loc, no))
{
// if (t->flag & (T_EDIT|T_POSE)) {
{
/* Exclude editmesh if using proportional edit */
if ((obedit->type == OB_MESH) && (t->flag & T_PROP_EDIT)) {
- t->tsnap.modeSelect = SNAP_NOT_OBEDIT;
+ t->tsnap.modeSelect = SNAP_NOT_ACTIVE;
}
else {
- t->tsnap.modeSelect = t->tsnap.snap_self ? SNAP_ALL : SNAP_NOT_OBEDIT;
+ t->tsnap.modeSelect = t->tsnap.snap_self ? SNAP_ALL : SNAP_NOT_ACTIVE;
}
}
/* Object mode */
if (t->tsnap.mode == SCE_SNAP_MODE_VOLUME) {
found = peelObjectsTransform(
- t, mval, t->tsnap.modeSelect,
+ t, mval,
(t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0,
loc, no, NULL);
}
else {
zero_v3(no); /* objects won't set this */
found = snapObjectsTransform(
- t, mval, t->tsnap.modeSelect, &dist_px,
+ t, mval, &dist_px,
loc, no);
}
}
bool snapObjectsTransform(
- TransInfo *t, const float mval[2], SnapSelect snap_select,
+ TransInfo *t, const float mval[2],
float *dist_px,
float r_loc[3], float r_no[3])
{
return ED_transform_snap_object_project_view3d_ex(
t->tsnap.object_context,
+ t->scene->toolsettings->snap_mode,
&(const struct SnapObjectParams){
- .snap_select = snap_select,
- .snap_to = t->scene->toolsettings->snap_mode,
- .use_object_edit = (t->flag & T_EDIT) != 0,
- .use_object_active = (t->options & CTX_GPENCIL_STROKES) == 0,
+ .snap_select = ((t->options & CTX_GPENCIL_STROKES) != 0) ? SNAP_NOT_ACTIVE : t->tsnap.modeSelect,
+ .use_object_edit_cage = (t->flag & T_EDIT) != 0,
},
mval, dist_px, NULL,
r_loc, r_no, NULL);
bool peelObjectsSnapContext(
SnapObjectContext *sctx,
- const float mval[2], SnapSelect snap_select, bool use_peel_object,
+ const float mval[2],
+ const struct SnapObjectParams *params,
+ const bool use_peel_object,
/* return args */
float r_loc[3], float r_no[3], float *r_thickness)
{
ListBase depths_peel = {0};
ED_transform_snap_object_project_all_view3d_ex(
sctx,
- &(const struct SnapObjectParams){
- .snap_to = SCE_SNAP_MODE_FACE,
- .snap_select = snap_select,
- .use_object_edit = true,
- },
+ params,
mval, -1.0f, false,
&depths_peel);
bool peelObjectsTransform(
TransInfo *t,
- const float mval[2], SnapSelect snap_select, bool use_peel_object,
+ const float mval[2],
+ const bool use_peel_object,
/* return args */
float r_loc[3], float r_no[3], float *r_thickness)
{
return peelObjectsSnapContext(
t->tsnap.object_context,
- mval, snap_select, use_peel_object,
+ mval,
+ &(const struct SnapObjectParams){
+ .snap_select = ((t->options & CTX_GPENCIL_STROKES) != 0) ? SNAP_NOT_ACTIVE : t->tsnap.modeSelect,
+ .use_object_edit_cage = (t->flag & T_EDIT) != 0,
+ },
+ use_peel_object,
r_loc, r_no, r_thickness);
}
float imat[4][4];
float timat[3][3]; /* transpose inverse matrix for normals */
float ray_start_local[3], ray_normal_local[3];
- float local_scale, local_depth, len_diff;
+ float local_scale, local_depth;
invert_m4_m4(imat, obmat);
transpose_m3_m4(timat, imat);
* been *inside* boundbox, leading to snap failures (see T38409).
* Note also ar might be null (see T38435), in this case we assume ray_start is ok!
*/
+ float len_diff = 0.0f;
if (do_ray_start_correction) {
/* We *need* a reasonably valid len_diff in this case.
* Use BHVTree to find the closest face from ray_start_local.
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
/* Compute and store result. */
- BLI_bvhtree_find_nearest(
- treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata);
- if (nearest.index != -1) {
+ if (BLI_bvhtree_find_nearest(
+ treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata) != -1)
+ {
len_diff = sqrtf(nearest.dist_sq);
+ float ray_org_local[3];
+
+ copy_v3_v3(ray_org_local, ray_origin);
+ mul_m4_v3(imat, ray_org_local);
+
+ /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far
+ * away ray_start values (as returned in case of ortho view3d), see T38358.
+ */
+ len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
+ madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local,
+ len_diff - len_v3v3(ray_start_local, ray_org_local));
+ local_depth -= len_diff;
}
}
- float ray_org_local[3];
-
- copy_v3_v3(ray_org_local, ray_origin);
- mul_m4_v3(imat, ray_org_local);
-
- /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far
- * away ray_start values (as returned in case of ortho view3d), see T38358.
- */
- len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
- madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local,
- len_diff - len_v3v3(ray_start_local, ray_org_local));
- local_depth -= len_diff;
- }
- else {
- len_diff = 0.0f;
}
switch (snap_to) {
static bool snapObjectsRay(
SnapObjectContext *sctx,
- SnapSelect snap_select, const short snap_to,
+ const unsigned short snap_to, const SnapSelect snap_select,
+ const bool use_object_edit_cage,
const float mval[2], float *dist_px,
- /* special handling of active and edit objects */
- Base *base_act, Object *obedit,
const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth,
/* return args */
float r_loc[3], float r_no[3], int *r_index,
Object **r_ob, float r_obmat[4][4],
ListBase *r_hit_list)
{
- Base *base;
bool retval = false;
- bool snap_obedit_first = snap_select == SNAP_ALL && obedit;
unsigned int ob_index = 0;
+ Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL;
+ Base *base_act = sctx->scene->basact;
- if (snap_obedit_first) {
- Object *ob = obedit;
-
- retval |= snapObject(
- sctx, ob, ob->obmat, true, snap_to,
- mval, dist_px, ob_index++,
- ray_start, ray_normal, ray_origin, ray_depth,
- r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
+ bool ignore_object_selected = false, ignore_object_active = false;
+ switch (snap_select) {
+ case SNAP_ALL:
+ break;
+ case SNAP_NOT_SELECTED:
+ ignore_object_selected = true;
+ break;
+ case SNAP_NOT_ACTIVE:
+ ignore_object_active = true;
+ break;
}
-
- for (base = sctx->scene->base.first; base != NULL; base = base->next) {
+ for (Base *base = sctx->scene->base.first; base != NULL; base = base->next) {
if ((BASE_VISIBLE_BGMODE(sctx->v3d_data.v3d, sctx->scene, base)) &&
(base->flag & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 &&
- ((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) ||
- (ELEM(snap_select, SNAP_ALL, SNAP_NOT_OBEDIT) && base != base_act)))
+ !((ignore_object_selected && (base->flag & (SELECT | BA_WAS_SEL))) ||
+ (ignore_object_active && base == base_act)))
{
Object *ob = base->object;
- Object *ob_snap = ob;
- bool use_obedit = false;
if (ob->transflag & OB_DUPLI) {
DupliObject *dupli_ob;
free_object_duplilist(lb);
}
- if (obedit) {
- if ((ob == obedit) &&
- (snap_obedit_first || (snap_select == SNAP_NOT_OBEDIT)))
- {
- continue;
- }
-
- if (ob->data == obedit->data) {
- /* for linked objects, use the same object but a different matrix */
- use_obedit = true;
- ob_snap = obedit;
- }
- }
+ bool use_obedit = (obedit != NULL) && (ob->data == obedit->data);
+ Object *ob_snap = use_obedit ? obedit : ob;
retval |= snapObject(
sctx, ob_snap, ob->obmat, use_obedit, snap_to,
bool ED_transform_snap_object_project_ray_ex(
SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3], float *ray_depth,
float r_loc[3], float r_no[3], int *r_index,
Object **r_ob, float r_obmat[4][4])
{
- Base *base_act = params->use_object_active ? sctx->scene->basact : NULL;
- Object *obedit = params->use_object_edit ? sctx->scene->obedit : NULL;
-
return snapObjectsRay(
sctx,
- params->snap_select, params->snap_to,
+ snap_to, params->snap_select, params->use_object_edit_cage,
NULL, NULL,
- base_act, obedit,
ray_start, ray_normal, ray_start, ray_depth,
- r_loc, r_no, r_index,
- r_ob, r_obmat, NULL);
+ r_loc, r_no, r_index, r_ob, r_obmat, NULL);
}
/**
*/
bool ED_transform_snap_object_project_ray_all(
SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3],
float ray_depth, bool sort,
ListBase *r_hit_list)
{
- Base *base_act = params->use_object_active ? sctx->scene->basact : NULL;
- Object *obedit = params->use_object_edit ? sctx->scene->obedit : NULL;
-
if (ray_depth == -1.0f) {
ray_depth = BVH_RAYCAST_DIST_MAX;
}
bool retval = snapObjectsRay(
sctx,
- params->snap_select, params->snap_to,
+ snap_to, params->snap_select, params->use_object_edit_cage,
NULL, NULL,
- base_act, obedit,
ray_start, ray_normal, ray_start, &ray_depth,
NULL, NULL, NULL, NULL, NULL,
r_hit_list);
*/
static bool transform_snap_context_project_ray_impl(
SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3], float *ray_depth,
float r_co[3], float r_no[3])
{
/* try snap edge, then face if it fails */
ret = ED_transform_snap_object_project_ray_ex(
sctx,
- &(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
- .snap_to = SCE_SNAP_MODE_FACE,
- .use_object_edit = (sctx->scene->obedit != NULL),
- },
+ SCE_SNAP_MODE_FACE,
+ params,
ray_start, ray_normal, ray_depth,
r_co, r_no, NULL,
NULL, NULL);
bool ED_transform_snap_object_project_ray(
SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
const float ray_origin[3], const float ray_direction[3], float *ray_depth,
float r_co[3], float r_no[3])
{
return transform_snap_context_project_ray_impl(
sctx,
+ params,
ray_origin, ray_direction, ray_depth,
r_co, r_no);
}
static bool transform_snap_context_project_view3d_mixed_impl(
SnapObjectContext *sctx,
+ const unsigned short snap_to_flag,
const struct SnapObjectParams *params,
const float mval[2], float *dist_px,
bool use_depth,
const int elem_type[3] = {SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE, SCE_SNAP_MODE_FACE};
- BLI_assert(params->snap_to_flag != 0);
- BLI_assert((params->snap_to_flag & ~(1 | 2 | 4)) == 0);
-
- struct SnapObjectParams params_temp = *params;
+ BLI_assert(snap_to_flag != 0);
+ BLI_assert((snap_to_flag & ~(1 | 2 | 4)) == 0);
for (int i = 0; i < 3; i++) {
- if ((params->snap_to_flag & (1 << i)) && (is_hit == false || use_depth)) {
+ if ((snap_to_flag & (1 << i)) && (is_hit == false || use_depth)) {
if (use_depth == false) {
ray_depth = BVH_RAYCAST_DIST_MAX;
}
- params_temp.snap_to = elem_type[i];
-
if (ED_transform_snap_object_project_view3d(
sctx,
- ¶ms_temp,
+ elem_type[i], params,
mval, dist_px, &ray_depth,
r_co, r_no))
{
*/
bool ED_transform_snap_object_project_view3d_mixed(
SnapObjectContext *sctx,
+ const unsigned short snap_to_flag,
const struct SnapObjectParams *params,
const float mval_fl[2], float *dist_px,
bool use_depth,
{
return transform_snap_context_project_view3d_mixed_impl(
sctx,
- params,
+ snap_to_flag, params,
mval_fl, dist_px, use_depth,
r_co, r_no);
}
bool ED_transform_snap_object_project_view3d_ex(
SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float mval[2], float *dist_px,
float *ray_depth,
return false;
}
- Base *base_act = params->use_object_active ? sctx->scene->basact : NULL;
- Object *obedit = params->use_object_edit ? sctx->scene->obedit : NULL;
return snapObjectsRay(
sctx,
- params->snap_select, params->snap_to,
+ snap_to, params->snap_select, params->use_object_edit_cage,
mval, dist_px,
- base_act, obedit,
ray_start, ray_normal, ray_orgigin, ray_depth,
r_loc, r_no, r_index, NULL, NULL, NULL);
}
bool ED_transform_snap_object_project_view3d(
SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float mval[2], float *dist_px,
float *ray_depth,
{
return ED_transform_snap_object_project_view3d_ex(
sctx,
+ snap_to,
params,
mval, dist_px,
ray_depth,
{
float ray_start[3], ray_normal[3];
- BLI_assert(params->snap_to == SCE_SNAP_MODE_FACE);
-
if (!ED_view3d_win_to_ray_ex(
sctx->v3d_data.ar, sctx->v3d_data.v3d,
mval, NULL, ray_normal, ray_start, true))
return ED_transform_snap_object_project_ray_all(
sctx,
+ SCE_SNAP_MODE_FACE,
params,
ray_start, ray_normal, ray_depth, sort,
r_hit_list);
struct GSet;
struct GPUVertPointLink;
struct GPUDrawObject;
+struct GridCommonGPUBuffer;
struct PBVH;
struct MVert;
void GPU_drawobject_free(struct DerivedMesh *dm);
-/* free special global multires grid buffer */
-void GPU_buffer_multires_free(bool force);
-
/* flag that controls data type to fill buffer with, a modifier will prepare. */
typedef enum {
GPU_BUFFER_VERTEX = 0,
const int *face_indices,
const int face_indices_len);
-GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid,
- unsigned int **grid_hidden, int gridsize, const struct CCGKey *key);
+GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(
+ int *grid_indices, int totgrid,unsigned int **grid_hidden, int gridsize, const struct CCGKey *key,
+ struct GridCommonGPUBuffer **grid_common_gpu_buffer);
GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(bool smooth_shading);
bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, struct GSet *bm_faces, bool show_diffuse_color);
void GPU_free_pbvh_buffers(GPU_PBVH_Buffers *buffers);
+void GPU_free_pbvh_buffer_multires(struct GridCommonGPUBuffer **grid_common_gpu_buffer);
#endif
static ThreadMutex buffer_mutex = BLI_MUTEX_INITIALIZER;
/* multires global buffer, can be used for many grids having the same grid size */
-static GPUBuffer *mres_glob_buffer = NULL;
-static int mres_prev_gridsize = -1;
-static GLenum mres_prev_index_type = 0;
-static unsigned mres_prev_totquad = 0;
+typedef struct GridCommonGPUBuffer {
+ GPUBuffer *mres_buffer;
+ int mres_prev_gridsize;
+ GLenum mres_prev_index_type;
+ unsigned mres_prev_totquad;
+} GridCommonGPUBuffer;
void GPU_buffer_material_finalize(GPUDrawObject *gdo, GPUBufferMaterial *matinfo, int totmat)
{
BLI_mutex_unlock(&buffer_mutex);
}
-void GPU_buffer_multires_free(bool force)
-{
- if (!mres_glob_buffer) {
- /* Early output, no need to lock in this case, */
- return;
- }
-
- if (force && BLI_thread_is_main()) {
- if (mres_glob_buffer) {
- if (mres_glob_buffer->id)
- glDeleteBuffers(1, &mres_glob_buffer->id);
- MEM_freeN(mres_glob_buffer);
- }
- }
- else {
- BLI_mutex_lock(&buffer_mutex);
- gpu_buffer_free_intern(mres_glob_buffer);
- BLI_mutex_unlock(&buffer_mutex);
- }
-
- mres_glob_buffer = NULL;
- mres_prev_gridsize = -1;
- mres_prev_index_type = 0;
- mres_prev_totquad = 0;
-}
-
-
void GPU_drawobject_free(DerivedMesh *dm)
{
GPUDrawObject *gdo;
const int *grid_indices;
int totgrid;
bool has_hidden;
+ bool is_index_buf_global; /* Means index_buf uses global bvh's grid_common_gpu_buffer, **DO NOT** free it! */
bool use_bmesh;
/* An element index buffer is used for smooth shading, but flat
* shading requires separate vertex normals so an index buffer is
* can't be used there. */
- if (buffers->smooth)
+ if (buffers->smooth) {
buffers->index_buf = GPU_buffer_alloc(sizeof(unsigned short) * tottri * 3);
+ buffers->is_index_buf_global = false;
+ }
if (buffers->index_buf) {
/* Fill the triangle buffer */
GPU_buffer_unlock(buffers->index_buf, GPU_BINDING_INDEX);
}
else {
- GPU_buffer_free(buffers->index_buf);
+ if (!buffers->is_index_buf_global) {
+ GPU_buffer_free(buffers->index_buf);
+ }
buffers->index_buf = NULL;
+ buffers->is_index_buf_global = false;
}
}
} (void)0
/* end FILL_QUAD_BUFFER */
-static GPUBuffer *gpu_get_grid_buffer(int gridsize, GLenum *index_type, unsigned *totquad)
+static GPUBuffer *gpu_get_grid_buffer(
+ int gridsize, GLenum *index_type, unsigned *totquad, GridCommonGPUBuffer **grid_common_gpu_buffer)
{
/* used in the FILL_QUAD_BUFFER macro */
BLI_bitmap * const *grid_hidden = NULL;
const int *grid_indices = NULL;
int totgrid = 1;
+ GridCommonGPUBuffer *gridbuff = *grid_common_gpu_buffer;
+
+ if (gridbuff == NULL) {
+ *grid_common_gpu_buffer = gridbuff = MEM_mallocN(sizeof(GridCommonGPUBuffer), __func__);
+ gridbuff->mres_buffer = NULL;
+ gridbuff->mres_prev_gridsize = -1;
+ gridbuff->mres_prev_index_type = 0;
+ gridbuff->mres_prev_totquad = 0;
+ }
+
/* VBO is already built */
- if (mres_glob_buffer && mres_prev_gridsize == gridsize) {
- *index_type = mres_prev_index_type;
- *totquad = mres_prev_totquad;
- return mres_glob_buffer;
+ if (gridbuff->mres_buffer && gridbuff->mres_prev_gridsize == gridsize) {
+ *index_type = gridbuff->mres_prev_index_type;
+ *totquad = gridbuff->mres_prev_totquad;
+ return gridbuff->mres_buffer;
}
/* we can't reuse old, delete the existing buffer */
- else if (mres_glob_buffer) {
- GPU_buffer_free(mres_glob_buffer);
+ else if (gridbuff->mres_buffer) {
+ GPU_buffer_free(gridbuff->mres_buffer);
}
/* Build new VBO */
if (gridsize * gridsize < USHRT_MAX) {
*index_type = GL_UNSIGNED_SHORT;
- FILL_QUAD_BUFFER(unsigned short, *totquad, mres_glob_buffer);
+ FILL_QUAD_BUFFER(unsigned short, *totquad, gridbuff->mres_buffer);
}
else {
*index_type = GL_UNSIGNED_INT;
- FILL_QUAD_BUFFER(unsigned int, *totquad, mres_glob_buffer);
+ FILL_QUAD_BUFFER(unsigned int, *totquad, gridbuff->mres_buffer);
}
- mres_prev_gridsize = gridsize;
- mres_prev_index_type = *index_type;
- mres_prev_totquad = *totquad;
- return mres_glob_buffer;
+ gridbuff->mres_prev_gridsize = gridsize;
+ gridbuff->mres_prev_index_type = *index_type;
+ gridbuff->mres_prev_totquad = *totquad;
+ return gridbuff->mres_buffer;
}
#define FILL_FAST_BUFFER(type_) \
} \
} (void)0
-GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid,
- BLI_bitmap **grid_hidden, int gridsize, const CCGKey *key)
+GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(
+ int *grid_indices, int totgrid, BLI_bitmap **grid_hidden, int gridsize, const CCGKey *key,
+ GridCommonGPUBuffer **grid_common_gpu_buffer)
{
GPU_PBVH_Buffers *buffers;
int totquad;
}
if (totquad == fully_visible_totquad) {
- buffers->index_buf = gpu_get_grid_buffer(gridsize, &buffers->index_type, &buffers->tot_quad);
+ buffers->index_buf = gpu_get_grid_buffer(
+ gridsize, &buffers->index_type, &buffers->tot_quad, grid_common_gpu_buffer);
buffers->has_hidden = false;
+ buffers->is_index_buf_global = true;
}
else {
buffers->tot_quad = totquad;
}
buffers->has_hidden = true;
+ buffers->is_index_buf_global = false;
}
/* Build coord/normal VBO */
const int use_short = (maxvert < USHRT_MAX);
/* Initialize triangle index buffer */
- if (buffers->index_buf)
+ if (buffers->index_buf && !buffers->is_index_buf_global)
GPU_buffer_free(buffers->index_buf);
+ buffers->is_index_buf_global = false;
buffers->index_buf = GPU_buffer_alloc((use_short ?
sizeof(unsigned short) :
sizeof(unsigned int)) * 3 * tottri);
}
else {
/* Memory map failed */
- GPU_buffer_free(buffers->index_buf);
+ if (!buffers->is_index_buf_global) {
+ GPU_buffer_free(buffers->index_buf);
+ }
buffers->index_buf = NULL;
+ buffers->is_index_buf_global = false;
}
}
else if (buffers->index_buf) {
- GPU_buffer_free(buffers->index_buf);
+ if (!buffers->is_index_buf_global) {
+ GPU_buffer_free(buffers->index_buf);
+ }
+ buffers->index_buf = NULL;
+ buffers->is_index_buf_global = false;
}
}
if (buffers) {
if (buffers->vert_buf)
GPU_buffer_free(buffers->vert_buf);
- if (buffers->index_buf && (buffers->tot_tri || buffers->has_hidden))
+ if (buffers->index_buf && !buffers->is_index_buf_global)
GPU_buffer_free(buffers->index_buf);
if (buffers->index_buf_fast)
GPU_buffer_free(buffers->index_buf_fast);
}
}
+void GPU_free_pbvh_buffer_multires(GridCommonGPUBuffer **grid_common_gpu_buffer)
+{
+ GridCommonGPUBuffer *gridbuff = *grid_common_gpu_buffer;
+
+ if (gridbuff) {
+ if (gridbuff->mres_buffer) {
+ BLI_mutex_lock(&buffer_mutex);
+ gpu_buffer_free_intern(gridbuff->mres_buffer);
+ BLI_mutex_unlock(&buffer_mutex);
+ }
+ MEM_freeN(gridbuff);
+ *grid_common_gpu_buffer = NULL;
+ }
+}
/* debug function, draws the pbvh BB */
void GPU_draw_pbvh_BB(float min[3], float max[3], bool leaf)
gpu_codegen_exit();
gpu_extensions_exit(); /* must come last */
- GPU_buffer_multires_free(true);
initialized = false;
}
*/
typedef struct Library {
ID id;
- ID *idblock;
struct FileData *filedata;
char name[1024]; /* path name used for reading, can be relative and edited in the outliner */
struct Library *parent; /* set for indirectly linked libs, used in the outliner and while reading */
struct PackedFile *packedfile;
+
+ int temp_index;
+ int _pad;
} Library;
enum eIconSizes {
unsigned int totvert; /* total number of points which define the curve (i.e. size of arrays in FPoints) */
/* value cache + settings */
- float curval; /* value stored from last time curve was evaluated */
+ float curval; /* value stored from last time curve was evaluated (not threadsafe, debug display only!) */
short flag; /* user-editable settings for this curve */
short extend; /* value-extending mode for this curve (does not cover */
short mix_mode;
char pad[2];
float mix_factor;
+ float mix_limit;
float offset[3];
+ float pad_f1;
} NormalEditModifierData;
/* NormalEditModifierData.mode */
"How much of generated normals to mix with exiting ones", 0.0f, 1.0f);
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_float(srna, "mix_limit", 1.0f, 0.0f, DEG2RADF(180.0f), "Max Angle",
+ "Maximum angle between old and new normals", 0.0f, DEG2RADF(180.0f));
+ RNA_def_property_subtype(prop, PROP_ANGLE);
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for selecting/weighting the affected areas");
prop = RNA_def_property(srna, "dimensions", PROP_FLOAT, PROP_XYZ_LENGTH);
RNA_def_property_array(prop, 3);
+ /* only for the transform-panel and conflicts with animating scale */
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_float_funcs(prop, "rna_Object_dimensions_get", "rna_Object_dimensions_set", NULL);
RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, 3);
RNA_def_property_ui_text(prop, "Dimensions", "Absolute bounding box dimensions of the object");
bool ret = ED_transform_snap_object_project_ray_ex(
sctx,
+ SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
- .snap_to = SCE_SNAP_MODE_FACE,
},
origin, direction, &ray_dist,
r_location, r_normal, r_index,
{
bAddon *bext = path_cmp_ptr->data;
if (BLI_findindex(&U.addons, bext) == -1) {
- BKE_report(reports, RPT_ERROR, "Addon is no longer valid");
+ BKE_report(reports, RPT_ERROR, "Add-on is no longer valid");
return;
}
BLI_strncpy(dummyapt.idname, dummyaddon.module, sizeof(dummyapt.idname));
if (strlen(identifier) >= sizeof(dummyapt.idname)) {
- BKE_reportf(reports, RPT_ERROR, "Registering addon-prefs class: '%s' is too long, maximum length is %d",
+ BKE_reportf(reports, RPT_ERROR, "Registering add-on preferences class: '%s' is too long, maximum length is %d",
identifier, (int)sizeof(dummyapt.idname));
return NULL;
}
srna = RNA_def_struct(brna, "Addon", NULL);
RNA_def_struct_sdna(srna, "bAddon");
RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
- RNA_def_struct_ui_text(srna, "Addon", "Python addons to be loaded automatically");
+ RNA_def_struct_ui_text(srna, "Add-on", "Python add-ons to be loaded automatically");
prop = RNA_def_property(srna, "module", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Module", "Module name");
PropertyRNA *prop;
srna = RNA_def_struct(brna, "AddonPreferences", NULL);
- RNA_def_struct_ui_text(srna, "Addon Preferences", "");
+ RNA_def_struct_ui_text(srna, "Add-on Preferences", "");
RNA_def_struct_sdna(srna, "bAddon"); /* WARNING: only a bAddon during registration */
RNA_def_struct_refine_func(srna, "rna_AddonPref_refine");
RNA_def_property_string_sdna(prop, NULL, "pythondir");
RNA_def_property_ui_text(prop, "Python Scripts Directory",
"Alternate script path, matching the default layout with subdirs: "
- "startup, addons & modules (requires restart)");
+ "startup, add-ons & modules (requires restart)");
/* TODO, editing should reset sys.path! */
prop = RNA_def_property(srna, "i18n_branches_directory", PROP_STRING, PROP_DIRPATH);
func = RNA_def_function(srna, "remove", "rna_userdef_addon_remove");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove add-on");
- parm = RNA_def_pointer(func, "addon", "Addon", "", "Addon to remove");
+ parm = RNA_def_pointer(func, "addon", "Addon", "", "Add-on to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
}
prop = RNA_def_property(srna, "addons", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "addons", NULL);
RNA_def_property_struct_type(prop, "Addon");
- RNA_def_property_ui_text(prop, "Addon", "");
+ RNA_def_property_ui_text(prop, "Add-on", "");
rna_def_userdef_addon_collection(brna, prop);
prop = RNA_def_property(srna, "autoexec_paths", PROP_COLLECTION, PROP_NONE);
/* Note this modifies nos_new in-place. */
static void mix_normals(
const float mix_factor, MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup,
- const short mix_mode,
+ const float mix_limit, const short mix_mode,
const int num_verts, MLoop *mloop, float (*nos_old)[3], float (*nos_new)[3], const int num_loops)
{
/* Mix with org normals... */
case MOD_NORMALEDIT_MIX_COPY:
break;
}
- interp_v3_v3v3_slerp_safe(*no_new, *no_old, *no_new, fac);
+
+ interp_v3_v3v3_slerp_safe(*no_new, *no_old, *no_new,
+ (mix_limit < M_PI) ? min_ff(fac, mix_limit / angle_v3v3(*no_new, *no_old)) : fac);
}
MEM_SAFE_FREE(facs);
static void normalEditModifier_do_radial(
NormalEditModifierData *smd, Object *ob, DerivedMesh *dm,
short (*clnors)[2], float (*loopnors)[3], float (*polynors)[3],
- const short mix_mode, const float mix_factor,
+ const short mix_mode, const float mix_factor, const float mix_limit,
MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup,
MVert *mvert, const int num_verts, MEdge *medge, const int num_edges,
MLoop *mloop, const int num_loops, MPoly *mpoly, const int num_polys)
if (loopnors) {
mix_normals(mix_factor, dvert, defgrp_index, use_invert_vgroup,
- mix_mode, num_verts, mloop, loopnors, nos, num_loops);
+ mix_limit, mix_mode, num_verts, mloop, loopnors, nos, num_loops);
}
if (polygons_check_flip(mloop, nos, dm->getLoopDataLayout(dm), mpoly, polynors, num_polys)) {
static void normalEditModifier_do_directional(
NormalEditModifierData *smd, Object *ob, DerivedMesh *dm,
short (*clnors)[2], float (*loopnors)[3], float (*polynors)[3],
- const short mix_mode, const float mix_factor,
+ const short mix_mode, const float mix_factor, const float mix_limit,
MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup,
MVert *mvert, const int num_verts, MEdge *medge, const int num_edges,
MLoop *mloop, const int num_loops, MPoly *mpoly, const int num_polys)
if (loopnors) {
mix_normals(mix_factor, dvert, defgrp_index, use_invert_vgroup,
- mix_mode, num_verts, mloop, loopnors, nos, num_loops);
+ mix_limit, mix_mode, num_verts, mloop, loopnors, nos, num_loops);
}
if (polygons_check_flip(mloop, nos, dm->getLoopDataLayout(dm), mpoly, polynors, num_polys)) {
const bool use_invert_vgroup = ((smd->flag & MOD_NORMALEDIT_INVERT_VGROUP) != 0);
const bool use_current_clnors = !((smd->mix_mode == MOD_NORMALEDIT_MIX_COPY) &&
(smd->mix_factor == 1.0f) &&
- (smd->defgrp_name[0] == '\0'));
+ (smd->defgrp_name[0] == '\0') &&
+ (smd->mix_limit == M_PI));
int defgrp_index;
MDeformVert *dvert;
if (smd->mode == MOD_NORMALEDIT_MODE_RADIAL) {
normalEditModifier_do_radial(
smd, ob, dm, clnors, loopnors, polynors,
- smd->mix_mode, smd->mix_factor, dvert, defgrp_index, use_invert_vgroup,
+ smd->mix_mode, smd->mix_factor, smd->mix_limit, dvert, defgrp_index, use_invert_vgroup,
mvert, num_verts, medge, num_edges, mloop, num_loops, mpoly, num_polys);
}
else if (smd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) {
normalEditModifier_do_directional(
smd, ob, dm, clnors, loopnors, polynors,
- smd->mix_mode, smd->mix_factor, dvert, defgrp_index, use_invert_vgroup,
+ smd->mix_mode, smd->mix_factor, smd->mix_limit, dvert, defgrp_index, use_invert_vgroup,
mvert, num_verts, medge, num_edges, mloop, num_loops, mpoly, num_polys);
}
smd->mix_mode = MOD_NORMALEDIT_MIX_COPY;
smd->mix_factor = 1.0f;
+ smd->mix_limit = M_PI;
}
static void copyData(ModifierData *md, ModifierData *target)
/* structSize */ sizeof(ShapeKeyModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ NULL,
extern "C" {
#endif
+#include "BLI_math_geom.h"
+
struct RayObject;
/* Ray Hints */
#ifdef RE_RAYCOUNTER
RayCounter *raycounter;
#endif
+
+ /* Precalculated coefficients for watertight intersection check. */
+ struct IsectRayPrecalc isect_precalc;
} Isect;
/* ray types */
/* Ray Triangle/Quad Intersection */
-MALWAYS_INLINE int isec_tri_quad(float start[3], float dir[3], RayFace *face, float uv[2], float *lambda)
+MALWAYS_INLINE int isec_tri_quad(float start[3], const struct IsectRayPrecalc *isect_precalc, RayFace *face, float r_uv[2], float *lambda)
{
- float co1[3], co2[3], co3[3], co4[3];
- float t0[3], t1[3], x[3], r[3], m[3], u, v, divdet, det1, l;
- int quad;
-
- quad = RE_rayface_isQuad(face);
-
- copy_v3_v3(co1, face->v1);
- copy_v3_v3(co2, face->v2);
- copy_v3_v3(co3, face->v3);
-
- copy_v3_v3(r, dir);
-
- /* intersect triangle */
- sub_v3_v3v3(t0, co3, co2);
- sub_v3_v3v3(t1, co3, co1);
-
- cross_v3_v3v3(x, r, t1);
- divdet = dot_v3v3(t0, x);
-
- sub_v3_v3v3(m, start, co3);
- det1 = dot_v3v3(m, x);
-
- if (divdet != 0.0f) {
- divdet = 1.0f / divdet;
- v = det1 * divdet;
-
- if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) {
- float cros[3];
-
- cross_v3_v3v3(cros, m, t0);
- u = divdet * dot_v3v3(cros, r);
-
- if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON)) {
- l = divdet * dot_v3v3(cros, t1);
-
- /* check if intersection is within ray length */
- if (l > -RE_RAYTRACE_EPSILON && l < *lambda) {
- uv[0] = u;
- uv[1] = v;
- *lambda = l;
- return 1;
- }
- }
+ float uv[2], l;
+
+ if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v2, face->v3, &l, uv)) {
+ /* check if intersection is within ray length */
+ if (l > -RE_RAYTRACE_EPSILON && l < *lambda) {
+ r_uv[0] = uv[0];
+ r_uv[1] = uv[1];
+ *lambda = l;
+ return 1;
}
}
/* intersect second triangle in quad */
- if (quad) {
- copy_v3_v3(co4, face->v4);
- sub_v3_v3v3(t0, co3, co4);
- divdet = dot_v3v3(t0, x);
-
- if (divdet != 0.0f) {
- divdet = 1.0f / divdet;
- v = det1 * divdet;
-
- if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) {
- float cros[3];
-
- cross_v3_v3v3(cros, m, t0);
- u = divdet * dot_v3v3(cros, r);
-
- if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON)) {
- l = divdet * dot_v3v3(cros, t1);
-
- if (l > -RE_RAYTRACE_EPSILON && l < *lambda) {
- uv[0] = u;
- uv[1] = -(1.0f + v + u);
- *lambda = l;
- return 2;
- }
- }
+ if (RE_rayface_isQuad(face)) {
+ if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v3, face->v4, &l, uv)) {
+ /* check if intersection is within ray length */
+ if (l > -RE_RAYTRACE_EPSILON && l < *lambda) {
+ r_uv[0] = uv[0];
+ r_uv[1] = uv[1];
+ *lambda = l;
+ return 2;
}
}
}
MALWAYS_INLINE int isec_tri_quad_neighbour(float start[3], float dir[3], RayFace *face)
{
- float co1[3], co2[3], co3[3], co4[3];
- float t0[3], t1[3], x[3], r[3], m[3], u, v, divdet, det1;
- int quad;
-
- quad = RE_rayface_isQuad(face);
+ float r[3];
+ struct IsectRayPrecalc isect_precalc;
+ float uv[2], l;
- copy_v3_v3(co1, face->v1);
- copy_v3_v3(co2, face->v2);
- copy_v3_v3(co3, face->v3);
negate_v3_v3(r, dir); /* note, different than above function */
- /* intersect triangle */
- sub_v3_v3v3(t0, co3, co2);
- sub_v3_v3v3(t1, co3, co1);
-
- cross_v3_v3v3(x, r, t1);
- divdet = dot_v3v3(t0, x);
-
- sub_v3_v3v3(m, start, co3);
- det1 = dot_v3v3(m, x);
-
- if (divdet != 0.0f) {
- divdet = 1.0f / divdet;
- v = det1 * divdet;
-
- if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) {
- float cros[3];
-
- cross_v3_v3v3(cros, m, t0);
- u = divdet * dot_v3v3(cros, r);
+ isect_ray_tri_watertight_v3_precalc(&isect_precalc, r);
- if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON))
- return 1;
- }
+ if (isect_ray_tri_watertight_v3(start, &isect_precalc, face->v1, face->v2, face->v3, &l, uv)) {
+ return 1;
}
/* intersect second triangle in quad */
- if (quad) {
- copy_v3_v3(co4, face->v4);
- sub_v3_v3v3(t0, co3, co4);
- divdet = dot_v3v3(t0, x);
-
- if (divdet != 0.0f) {
- divdet = 1.0f / divdet;
- v = det1 * divdet;
-
- if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) {
- float cros[3];
-
- cross_v3_v3v3(cros, m, t0);
- u = divdet * dot_v3v3(cros, r);
-
- if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON))
- return 2;
- }
+ if (RE_rayface_isQuad(face)) {
+ if (isect_ray_tri_watertight_v3(start, &isect_precalc, face->v1, face->v3, face->v4, &l, uv)) {
+ return 2;
}
}
RE_RC_COUNT(is->raycounter->faces.test);
dist = is->dist;
- ok = isec_tri_quad(is->start, is->dir, face, uv, &dist);
+ ok = isec_tri_quad(is->start, &is->isect_precalc, face, uv, &dist);
if (ok) {
{
int i;
+ /* Pre-calculate orientation for watertight intersection checks. */
+ isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir);
+
RE_RC_COUNT(isec->raycounter->raycast.test);
/* setup vars used on raycast */
return "Unknown";
}
-static int passtype_from_name(const char *str)
+static int passtype_from_name(const char *str, int passflag)
{
+ /* We do not really support several pass of the same types, so in case we are opening an EXR file with several pass
+ * names detected as same pass type, only return that pass type the first time, and return 'uknown' for the others.
+ * See T48466. */
+#define RETURN_PASS(_passtype) return (passflag & (_passtype)) ? 0 : (_passtype)
+
if (STRPREFIX(str, "Combined"))
- return SCE_PASS_COMBINED;
+ RETURN_PASS(SCE_PASS_COMBINED);
if (STRPREFIX(str, "Depth"))
- return SCE_PASS_Z;
+ RETURN_PASS(SCE_PASS_Z);
if (STRPREFIX(str, "Vector"))
- return SCE_PASS_VECTOR;
+ RETURN_PASS(SCE_PASS_VECTOR);
if (STRPREFIX(str, "Normal"))
- return SCE_PASS_NORMAL;
+ RETURN_PASS(SCE_PASS_NORMAL);
if (STRPREFIX(str, "UV"))
- return SCE_PASS_UV;
+ RETURN_PASS(SCE_PASS_UV);
if (STRPREFIX(str, "Color"))
- return SCE_PASS_RGBA;
+ RETURN_PASS(SCE_PASS_RGBA);
if (STRPREFIX(str, "Emit"))
- return SCE_PASS_EMIT;
+ RETURN_PASS(SCE_PASS_EMIT);
if (STRPREFIX(str, "Diffuse"))
- return SCE_PASS_DIFFUSE;
+ RETURN_PASS(SCE_PASS_DIFFUSE);
if (STRPREFIX(str, "Spec"))
- return SCE_PASS_SPEC;
+ RETURN_PASS(SCE_PASS_SPEC);
if (STRPREFIX(str, "Shadow"))
- return SCE_PASS_SHADOW;
+ RETURN_PASS(SCE_PASS_SHADOW);
if (STRPREFIX(str, "AO"))
- return SCE_PASS_AO;
+ RETURN_PASS(SCE_PASS_AO);
if (STRPREFIX(str, "Env"))
- return SCE_PASS_ENVIRONMENT;
+ RETURN_PASS(SCE_PASS_ENVIRONMENT);
if (STRPREFIX(str, "Indirect"))
- return SCE_PASS_INDIRECT;
+ RETURN_PASS(SCE_PASS_INDIRECT);
if (STRPREFIX(str, "Reflect"))
- return SCE_PASS_REFLECT;
+ RETURN_PASS(SCE_PASS_REFLECT);
if (STRPREFIX(str, "Refract"))
- return SCE_PASS_REFRACT;
+ RETURN_PASS(SCE_PASS_REFRACT);
if (STRPREFIX(str, "IndexOB"))
- return SCE_PASS_INDEXOB;
+ RETURN_PASS(SCE_PASS_INDEXOB);
if (STRPREFIX(str, "IndexMA"))
- return SCE_PASS_INDEXMA;
+ RETURN_PASS(SCE_PASS_INDEXMA);
if (STRPREFIX(str, "Mist"))
- return SCE_PASS_MIST;
+ RETURN_PASS(SCE_PASS_MIST);
if (STRPREFIX(str, "RayHits"))
- return SCE_PASS_RAYHITS;
+ RETURN_PASS(SCE_PASS_RAYHITS);
if (STRPREFIX(str, "DiffDir"))
- return SCE_PASS_DIFFUSE_DIRECT;
+ RETURN_PASS(SCE_PASS_DIFFUSE_DIRECT);
if (STRPREFIX(str, "DiffInd"))
- return SCE_PASS_DIFFUSE_INDIRECT;
+ RETURN_PASS(SCE_PASS_DIFFUSE_INDIRECT);
if (STRPREFIX(str, "DiffCol"))
- return SCE_PASS_DIFFUSE_COLOR;
+ RETURN_PASS(SCE_PASS_DIFFUSE_COLOR);
if (STRPREFIX(str, "GlossDir"))
- return SCE_PASS_GLOSSY_DIRECT;
+ RETURN_PASS(SCE_PASS_GLOSSY_DIRECT);
if (STRPREFIX(str, "GlossInd"))
- return SCE_PASS_GLOSSY_INDIRECT;
+ RETURN_PASS(SCE_PASS_GLOSSY_INDIRECT);
if (STRPREFIX(str, "GlossCol"))
- return SCE_PASS_GLOSSY_COLOR;
+ RETURN_PASS(SCE_PASS_GLOSSY_COLOR);
if (STRPREFIX(str, "TransDir"))
- return SCE_PASS_TRANSM_DIRECT;
+ RETURN_PASS(SCE_PASS_TRANSM_DIRECT);
if (STRPREFIX(str, "TransInd"))
- return SCE_PASS_TRANSM_INDIRECT;
+ RETURN_PASS(SCE_PASS_TRANSM_INDIRECT);
if (STRPREFIX(str, "TransCol"))
- return SCE_PASS_TRANSM_COLOR;
+ RETURN_PASS(SCE_PASS_TRANSM_COLOR);
if (STRPREFIX(str, "SubsurfaceDir"))
- return SCE_PASS_SUBSURFACE_DIRECT;
+ RETURN_PASS(SCE_PASS_SUBSURFACE_DIRECT);
if (STRPREFIX(str, "SubsurfaceInd"))
- return SCE_PASS_SUBSURFACE_INDIRECT;
+ RETURN_PASS(SCE_PASS_SUBSURFACE_INDIRECT);
if (STRPREFIX(str, "SubsurfaceCol"))
- return SCE_PASS_SUBSURFACE_COLOR;
+ RETURN_PASS(SCE_PASS_SUBSURFACE_COLOR);
return 0;
+
+#undef RETURN_PASS
}
BLI_addtail(&rl->passes, rpass);
rpass->channels = totchan;
- rpass->passtype = passtype_from_name(str);
- if (rpass->passtype == 0) printf("unknown pass %s\n", str);
+ rpass->passtype = passtype_from_name(str, rl->passflag);
+ if (rpass->passtype == 0)
+ printf("unknown pass %s\n", str);
rl->passflag |= rpass->passtype;
/* channel id chars */
}
BKE_reportf(reports, RPT_ERROR,
- "Engine '%s' not available for scene '%s' "
- "(an addon may need to be installed or enabled)",
+ "Engine '%s' not available for scene '%s' (an add-on may need to be installed or enabled)",
sce->r.engine, sce->id.name + 2);
}
}
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx) RET_NONE
bool ED_transform_snap_object_project_ray_ex(
struct SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3], float *ray_depth,
/* return args */
)
if(WITH_PYTHON_INSTALL_NUMPY)
+ set(PYTHON_NUMPY_VERSION 1.9)
+ if(MSVC_VERSION EQUAL 1900)
+ set(PYTHON_NUMPY_VERSION 1.11)
+ endif()
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages
COMMAND ${CMAKE_COMMAND} -E
make_directory ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages/numpy
COMMAND ${CMAKE_COMMAND} -E
- tar xzvf "${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_1.9.tar.gz"
+ tar xzvf "${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_${PYTHON_NUMPY_VERSION}.tar.gz"
DEPENDS
- ${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_1.9.tar.gz
+ ${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_${PYTHON_NUMPY_VERSION}.tar.gz
${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages
)
BLI_argsPrintArgDoc(ba, "--");
+ printf("\n");
printf("Other Options:\n");
BLI_argsPrintOtherDoc(ba);
+ /* keep last args */
+ printf("\n");
+ printf("Experimental Features:\n");
+ BLI_argsPrintArgDoc(ba, "--enable-new-depsgraph");
+
+ printf("\n");
printf("Argument Parsing:\n");
printf("\tArguments must be separated by white space, eg:\n");
printf("\t# blender -ba test.blend\n");
#endif
printf(" $PYTHONHOME Path to the python directory, eg. /usr/lib/python.\n\n");
- /* keep last */
- printf("\n");
- printf("Experimental Features:\n");
- BLI_argsPrintArgDoc(ba, "--enable-new-depsgraph");
-
exit(0);
return 0;
"<options> <file(s)>\n"
"\tPlayback <file(s)>, only operates this way when not running in background.\n"
"\t\t-p <sx> <sy>\tOpen with lower left corner at <sx>, <sy>\n"
-"\t\t-m\t\tRead from disk (Don't buffer)\n"
+"\t\t-m\t\tRead from disk (Do not buffer)\n"
"\t\t-f <fps> <fps-base>\t\tSpecify FPS to start with\n"
"\t\t-j <frame>\tSet frame step to <frame>\n"
"\t\t-s <frame>\tPlay from <frame>\n"
}
static const char arg_handle_register_extension_doc[] =
-"\n\tRegister .blend extension, then exit (Windows only)"
+"\n\tRegister blend-file extension, then exit (Windows only)"
;
static const char arg_handle_register_extension_doc_silent[] =
-"\n\tSilently register .blend extension, then exit (Windows only)"
+"\n\tSilently register blend-file extension, then exit (Windows only)"
;
static int arg_handle_register_extension(int UNUSED(argc), const char **UNUSED(argv), void *data)
{