Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/intern
diff options
context:
space:
mode:
Diffstat (limited to 'intern')
-rw-r--r--intern/clog/CLG_log.h3
-rw-r--r--intern/clog/clog.c23
-rw-r--r--intern/cycles/blender/blender_mesh.cpp46
-rw-r--r--intern/cycles/blender/blender_session.cpp3
-rw-r--r--intern/cycles/device/CMakeLists.txt1
-rw-r--r--intern/cycles/device/opencl/device_opencl_impl.cpp8
-rw-r--r--intern/cycles/kernel/kernel_film.h2
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel_bake.cl14
-rw-r--r--intern/cycles/kernel/osl/osl_globals.h1
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp8
-rw-r--r--intern/cycles/render/buffers.cpp15
-rw-r--r--intern/cycles/render/buffers.h2
-rw-r--r--intern/cycles/render/film.cpp2
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm2
-rw-r--r--intern/guardedalloc/MEM_guardedalloc.h5
-rw-r--r--intern/guardedalloc/intern/leak_detector.cc19
-rw-r--r--intern/mantaflow/intern/manta_fluid_API.cpp4
-rw-r--r--intern/numaapi/source/build_config.h2
-rw-r--r--intern/softbody/admmpd_api.cpp289
-rw-r--r--intern/softbody/admmpd_api.h75
20 files changed, 331 insertions, 193 deletions
diff --git a/intern/clog/CLG_log.h b/intern/clog/CLG_log.h
index 7418623755c..a2841c5c8b3 100644
--- a/intern/clog/CLG_log.h
+++ b/intern/clog/CLG_log.h
@@ -132,13 +132,14 @@ void CLG_logf(CLG_LogType *lg,
const char *format,
...) _CLOG_ATTR_NONNULL(1, 3, 4, 5) _CLOG_ATTR_PRINTF_FORMAT(5, 6);
-/* Main initializer and distructor (per session, not logger). */
+/* Main initializer and destructor (per session, not logger). */
void CLG_init(void);
void CLG_exit(void);
void CLG_output_set(void *file_handle);
void CLG_output_use_basename_set(int value);
void CLG_output_use_timestamp_set(int value);
+void CLG_error_fn_set(void (*error_fn)(void *file_handle));
void CLG_fatal_fn_set(void (*fatal_fn)(void *file_handle));
void CLG_backtrace_fn_set(void (*fatal_fn)(void *file_handle));
diff --git a/intern/clog/clog.c b/intern/clog/clog.c
index d384b9a89e6..84b850f5042 100644
--- a/intern/clog/clog.c
+++ b/intern/clog/clog.c
@@ -98,6 +98,7 @@ typedef struct CLogContext {
} default_type;
struct {
+ void (*error_fn)(void *file_handle);
void (*fatal_fn)(void *file_handle);
void (*backtrace_fn)(void *file_handle);
} callbacks;
@@ -352,6 +353,13 @@ static CLG_LogType *clg_ctx_type_register(CLogContext *ctx, const char *identifi
return ty;
}
+static void clg_ctx_error_action(CLogContext *ctx)
+{
+ if (ctx->callbacks.error_fn != NULL) {
+ ctx->callbacks.error_fn(ctx->output_file);
+ }
+}
+
static void clg_ctx_fatal_action(CLogContext *ctx)
{
if (ctx->callbacks.fatal_fn != NULL) {
@@ -522,6 +530,10 @@ void CLG_logf(CLG_LogType *lg,
clg_ctx_backtrace(lg->ctx);
}
+ if (severity == CLG_SEVERITY_ERROR) {
+ clg_ctx_error_action(lg->ctx);
+ }
+
if (severity == CLG_SEVERITY_FATAL) {
clg_ctx_fatal_action(lg->ctx);
}
@@ -555,6 +567,12 @@ static void CLG_ctx_output_use_timestamp_set(CLogContext *ctx, int value)
}
}
+/** Action on error severity. */
+static void CLT_ctx_error_fn_set(CLogContext *ctx, void (*error_fn)(void *file_handle))
+{
+ ctx->callbacks.error_fn = error_fn;
+}
+
/** Action on fatal severity. */
static void CLG_ctx_fatal_fn_set(CLogContext *ctx, void (*fatal_fn)(void *file_handle))
{
@@ -674,6 +692,11 @@ void CLG_output_use_timestamp_set(int value)
CLG_ctx_output_use_timestamp_set(g_ctx, value);
}
+void CLG_error_fn_set(void (*error_fn)(void *file_handle))
+{
+ CLT_ctx_error_fn_set(g_ctx, error_fn);
+}
+
void CLG_fatal_fn_set(void (*fatal_fn)(void *file_handle))
{
CLG_ctx_fatal_fn_set(g_ctx, fatal_fn);
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index f4354d5166e..e40e1f5f001 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -923,48 +923,34 @@ static void create_subd_mesh(Scene *scene,
/* Sync */
-static BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b_ob,
- BL::Scene /*b_scene*/)
+static BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b_ob)
{
- BL::Object::modifiers_iterator b_mod;
+ if (b_ob.modifiers.length() > 0) {
+ BL::Modifier b_mod = b_ob.modifiers[b_ob.modifiers.length() - 1];
- for (b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
- if (!b_mod->is_a(&RNA_MeshSequenceCacheModifier)) {
- continue;
- }
-
- BL::MeshSequenceCacheModifier mesh_cache = BL::MeshSequenceCacheModifier(*b_mod);
+ if (b_mod.type() == BL::Modifier::type_MESH_SEQUENCE_CACHE) {
+ BL::MeshSequenceCacheModifier mesh_cache = BL::MeshSequenceCacheModifier(b_mod);
- if (MeshSequenceCacheModifier_has_velocity_get(&mesh_cache.ptr)) {
- return mesh_cache;
+ if (MeshSequenceCacheModifier_has_velocity_get(&mesh_cache.ptr)) {
+ return mesh_cache;
+ }
}
}
return BL::MeshSequenceCacheModifier(PointerRNA_NULL);
}
-static void sync_mesh_cached_velocities(BL::Object &b_ob,
- BL::Scene b_scene,
- Scene *scene,
- Mesh *mesh)
+static void sync_mesh_cached_velocities(BL::Object &b_ob, Scene *scene, Mesh *mesh)
{
if (scene->need_motion() == Scene::MOTION_NONE)
return;
- BL::MeshSequenceCacheModifier b_mesh_cache = object_mesh_cache_find(b_ob, b_scene);
+ BL::MeshSequenceCacheModifier b_mesh_cache = object_mesh_cache_find(b_ob);
if (!b_mesh_cache) {
return;
}
- /* Find or add attribute */
- float3 *P = &mesh->verts[0];
- Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
-
- if (!attr_mP) {
- attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
- }
-
if (!MeshSequenceCacheModifier_read_velocity_get(&b_mesh_cache.ptr)) {
return;
}
@@ -975,6 +961,14 @@ static void sync_mesh_cached_velocities(BL::Object &b_ob,
return;
}
+ /* Find or add attribute */
+ float3 *P = &mesh->verts[0];
+ Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+
+ if (!attr_mP) {
+ attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
+ }
+
/* Only export previous and next frame, we don't have any in between data. */
float motion_times[2] = {-1.0f, 1.0f};
for (int step = 0; step < 2; step++) {
@@ -1071,7 +1065,7 @@ void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph,
}
/* cached velocities (e.g. from alembic archive) */
- sync_mesh_cached_velocities(b_ob, b_depsgraph.scene(), scene, mesh);
+ sync_mesh_cached_velocities(b_ob, scene, mesh);
/* mesh fluid motion mantaflow */
sync_mesh_fluid_motion(b_ob, scene, mesh);
@@ -1095,7 +1089,7 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
}
/* Cached motion blur already exported. */
- BL::MeshSequenceCacheModifier mesh_cache = object_mesh_cache_find(b_ob, b_scene);
+ BL::MeshSequenceCacheModifier mesh_cache = object_mesh_cache_find(b_ob);
if (mesh_cache) {
return;
}
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index fb704b2a24a..bf9fc784d79 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -363,7 +363,8 @@ void BlenderSession::do_write_update_render_tile(RenderTile &rtile,
PassType pass_type = BlenderSync::get_pass_type(b_pass);
int components = b_pass.channels();
- rtile.buffers->set_pass_rect(pass_type, components, (float *)b_pass.rect());
+ rtile.buffers->set_pass_rect(
+ pass_type, components, (float *)b_pass.rect(), rtile.num_samples);
}
end_render_result(b_engine, b_rr, false, false, false);
diff --git a/intern/cycles/device/CMakeLists.txt b/intern/cycles/device/CMakeLists.txt
index ca366722eb7..466872e0557 100644
--- a/intern/cycles/device/CMakeLists.txt
+++ b/intern/cycles/device/CMakeLists.txt
@@ -67,6 +67,7 @@ set(LIB
cycles_render
cycles_kernel
cycles_util
+ ${BLENDER_GL_LIBRARIES}
)
if(WITH_CUDA_DYNLOAD)
diff --git a/intern/cycles/device/opencl/device_opencl_impl.cpp b/intern/cycles/device/opencl/device_opencl_impl.cpp
index e851749949d..f0683d12f1f 100644
--- a/intern/cycles/device/opencl/device_opencl_impl.cpp
+++ b/intern/cycles/device/opencl/device_opencl_impl.cpp
@@ -864,6 +864,11 @@ void OpenCLDevice::load_preview_kernels()
bool OpenCLDevice::wait_for_availability(const DeviceRequestedFeatures &requested_features)
{
+ if (requested_features.use_baking) {
+ /* For baking, kernels have already been loaded in load_required_kernels(). */
+ return true;
+ }
+
if (background) {
load_kernel_task_pool.wait_work();
use_preview_kernels = false;
@@ -1933,13 +1938,12 @@ void OpenCLDevice::bake(DeviceTask &task, RenderTile &rtile)
kernel_set_args(kernel, start_arg_index, sample);
enqueue_kernel(kernel, d_w, d_h);
+ clFinish(cqCommandQueue);
rtile.sample = sample + 1;
task.update_progress(&rtile, rtile.w * rtile.h);
}
-
- clFinish(cqCommandQueue);
}
static bool kernel_build_opencl_2(cl_device_id cdDevice)
diff --git a/intern/cycles/kernel/kernel_film.h b/intern/cycles/kernel/kernel_film.h
index 8344f4b4f47..17b69b6198b 100644
--- a/intern/cycles/kernel/kernel_film.h
+++ b/intern/cycles/kernel/kernel_film.h
@@ -47,7 +47,7 @@ ccl_device float4 film_get_pass_result(KernelGlobals *kg,
if (kernel_data.film.use_display_exposure) {
float exposure = kernel_data.film.exposure;
- pass_result *= make_float4(exposure, exposure, exposure, alpha);
+ pass_result *= make_float4(exposure, exposure, exposure, 1.0f);
}
}
else if (display_pass_components == 1) {
diff --git a/intern/cycles/kernel/kernels/opencl/kernel_bake.cl b/intern/cycles/kernel/kernels/opencl/kernel_bake.cl
index 041312b53cb..7b81e387467 100644
--- a/intern/cycles/kernel/kernels/opencl/kernel_bake.cl
+++ b/intern/cycles/kernel/kernels/opencl/kernel_bake.cl
@@ -12,12 +12,11 @@
__kernel void kernel_ocl_bake(
ccl_constant KernelData *data,
- ccl_global uint4 *input,
- ccl_global float4 *output,
+ ccl_global float *buffer,
KERNEL_BUFFER_PARAMS,
- int type, int filter, int sx, int sw, int offset, int sample)
+ int sx, int sy, int sw, int sh, int offset, int stride, int sample)
{
KernelGlobals kglobals, *kg = &kglobals;
@@ -27,12 +26,11 @@ __kernel void kernel_ocl_bake(
kernel_set_buffer_info(kg);
int x = sx + ccl_global_id(0);
+ int y = sy + ccl_global_id(1);
- if(x < sx + sw) {
-#ifdef __NO_BAKING__
- output[x] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-#else
- kernel_bake_evaluate(kg, input, output, (ShaderEvalType)type, filter, x, offset, sample);
+ if(x < sx + sw && y < sy + sh) {
+#ifndef __NO_BAKING__
+ kernel_bake_evaluate(kg, buffer, sample, x, y, offset, stride);
#endif
}
}
diff --git a/intern/cycles/kernel/osl/osl_globals.h b/intern/cycles/kernel/osl/osl_globals.h
index c06c9abd4c1..caca3c28c8d 100644
--- a/intern/cycles/kernel/osl/osl_globals.h
+++ b/intern/cycles/kernel/osl/osl_globals.h
@@ -90,6 +90,7 @@ struct OSLTraceData {
ShaderData sd;
bool setup;
bool init;
+ bool hit;
};
/* thread key for thread specific data lookup */
diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp
index 5292b5f8055..aee1e3a244e 100644
--- a/intern/cycles/kernel/osl/osl_services.cpp
+++ b/intern/cycles/kernel/osl/osl_services.cpp
@@ -1481,6 +1481,7 @@ bool OSLRenderServices::trace(TraceOpt &options,
tracedata->ray = ray;
tracedata->setup = false;
tracedata->init = true;
+ tracedata->hit = false;
tracedata->sd.osl_globals = sd->osl_globals;
KernelGlobals *kg = sd->osl_globals;
@@ -1492,7 +1493,8 @@ bool OSLRenderServices::trace(TraceOpt &options,
/* Raytrace, leaving out shadow opaque to avoid early exit. */
uint visibility = PATH_RAY_ALL_VISIBILITY - PATH_RAY_SHADOW_OPAQUE;
- return scene_intersect(kg, &ray, visibility, &tracedata->isect);
+ tracedata->hit = scene_intersect(kg, &ray, visibility, &tracedata->isect);
+ return tracedata->hit;
}
bool OSLRenderServices::getmessage(OSL::ShaderGlobals *sg,
@@ -1506,9 +1508,9 @@ bool OSLRenderServices::getmessage(OSL::ShaderGlobals *sg,
if (source == u_trace && tracedata->init) {
if (name == u_hit) {
- return set_attribute_int((tracedata->isect.prim != PRIM_NONE), type, derivatives, val);
+ return set_attribute_int(tracedata->hit, type, derivatives, val);
}
- else if (tracedata->isect.prim != PRIM_NONE) {
+ else if (tracedata->hit) {
if (name == u_hitdist) {
float f[3] = {tracedata->isect.t, 0.0f, 0.0f};
return set_attribute_float(f, type, derivatives, val);
diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp
index b26366af852..3607300cee6 100644
--- a/intern/cycles/render/buffers.cpp
+++ b/intern/cycles/render/buffers.cpp
@@ -459,7 +459,7 @@ bool RenderBuffers::get_pass_rect(
return false;
}
-bool RenderBuffers::set_pass_rect(PassType type, int components, float *pixels)
+bool RenderBuffers::set_pass_rect(PassType type, int components, float *pixels, int samples)
{
if (buffer.data() == NULL) {
return false;
@@ -482,8 +482,17 @@ bool RenderBuffers::set_pass_rect(PassType type, int components, float *pixels)
assert(pass.components == components);
for (int i = 0; i < size; i++, out += pass_stride, pixels += components) {
- for (int j = 0; j < components; j++) {
- out[j] = pixels[j];
+ if (pass.filter) {
+ /* Scale by the number of samples, inverse of what we do in get_pass_rect.
+ * A better solution would be to remove the need for set_pass_rect entirely,
+ * and change baking to bake multiple objects in a tile at once. */
+ for (int j = 0; j < components; j++) {
+ out[j] = pixels[j] * samples;
+ }
+ }
+ else {
+ /* For non-filtered passes just straight copy, these may contain non-float data. */
+ memcpy(out, pixels, sizeof(float) * components);
}
}
diff --git a/intern/cycles/render/buffers.h b/intern/cycles/render/buffers.h
index 06b6094e6c9..425400a2c08 100644
--- a/intern/cycles/render/buffers.h
+++ b/intern/cycles/render/buffers.h
@@ -92,7 +92,7 @@ class RenderBuffers {
const string &name, float exposure, int sample, int components, float *pixels);
bool get_denoising_pass_rect(
int offset, float exposure, int sample, int components, float *pixels);
- bool set_pass_rect(PassType type, int components, float *pixels);
+ bool set_pass_rect(PassType type, int components, float *pixels, int samples);
};
/* Display Buffer
diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp
index 7072fff4892..2da28222a7f 100644
--- a/intern/cycles/render/film.cpp
+++ b/intern/cycles/render/film.cpp
@@ -253,6 +253,8 @@ void Pass::add(PassType type, vector<Pass> &passes, const char *name)
case PASS_BAKE_PRIMITIVE:
case PASS_BAKE_DIFFERENTIAL:
pass.components = 4;
+ pass.exposure = false;
+ pass.filter = false;
break;
default:
assert(false);
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
index 62b0e48a7c1..f8e2f96d111 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.mm
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -415,7 +415,7 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa,
[parentWindow->getCocoaWindow() addChildWindow:m_window ordered:NSWindowAbove];
[m_window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary];
}
- else if (state != GHOST_kWindowStateFullScreen) {
+ else {
[m_window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
}
diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h
index 9c62b2396f6..c05bda030ad 100644
--- a/intern/guardedalloc/MEM_guardedalloc.h
+++ b/intern/guardedalloc/MEM_guardedalloc.h
@@ -215,6 +215,11 @@ extern const char *(*MEM_name_ptr)(void *vmemh);
* about memory leaks will be printed on exit. */
void MEM_init_memleak_detection(void);
+/** When this has been called and memory leaks have been detected, the process will have an exit
+ * code that indicates failure. This can be used for when checking for memory leaks with automated
+ * tests. */
+void MEM_enable_fail_on_memleak(void);
+
/* Switch allocator to slower but fully guarded mode. */
void MEM_use_guarded_allocator(void);
diff --git a/intern/guardedalloc/intern/leak_detector.cc b/intern/guardedalloc/intern/leak_detector.cc
index d7b6f749742..0ecf2ed8ba7 100644
--- a/intern/guardedalloc/intern/leak_detector.cc
+++ b/intern/guardedalloc/intern/leak_detector.cc
@@ -18,6 +18,8 @@
* \ingroup MEM
*/
+#include <cstdlib>
+
#include "MEM_guardedalloc.h"
#include "mallocn_intern.h"
@@ -28,6 +30,9 @@ char free_after_leak_detection_message[] =
"error, use the 'construct on first use' idiom.";
namespace {
+
+bool fail_on_memleak = false;
+
class MemLeakPrinter {
public:
~MemLeakPrinter()
@@ -42,6 +47,15 @@ class MemLeakPrinter {
leaked_blocks,
(double)mem_in_use / 1024 / 1024);
MEM_printmemlist();
+
+ if (fail_on_memleak) {
+ /* There are many other ways to change the exit code to failure here:
+ * - Make the destructor noexcept(false) and throw an exception.
+ * - Call exit(EXIT_FAILURE).
+ * - Call terminate().
+ */
+ abort();
+ }
}
};
} // namespace
@@ -59,3 +73,8 @@ void MEM_init_memleak_detection(void)
*/
static MemLeakPrinter printer;
}
+
+void MEM_enable_fail_on_memleak(void)
+{
+ fail_on_memleak = true;
+}
diff --git a/intern/mantaflow/intern/manta_fluid_API.cpp b/intern/mantaflow/intern/manta_fluid_API.cpp
index 530dbd49b7c..7f96a315a8e 100644
--- a/intern/mantaflow/intern/manta_fluid_API.cpp
+++ b/intern/mantaflow/intern/manta_fluid_API.cpp
@@ -456,7 +456,7 @@ int manta_smoke_ensure_fire(MANTA *smoke, struct FluidModifierData *fmd)
if (!smoke || !fmd)
return 0;
- int result = smoke->initFire(fmd);
+ bool result = smoke->initFire(fmd);
if (smoke->usingNoise()) {
result &= smoke->initFireHigh(fmd);
}
@@ -468,7 +468,7 @@ int manta_smoke_ensure_colors(MANTA *smoke, struct FluidModifierData *fmd)
if (!smoke || !fmd)
return 0;
- int result = smoke->initColors(fmd);
+ bool result = smoke->initColors(fmd);
if (smoke->usingNoise()) {
result &= smoke->initColorsHigh(fmd);
}
diff --git a/intern/numaapi/source/build_config.h b/intern/numaapi/source/build_config.h
index c6392532914..8e351f1c718 100644
--- a/intern/numaapi/source/build_config.h
+++ b/intern/numaapi/source/build_config.h
@@ -96,7 +96,7 @@
#elif defined(__QNXNTO__)
# define OS_QNX 1
#elif defined(__asmjs__) || defined(__wasm__)
-# define OS_ASMJS
+# define OS_ASMJS 1
#else
# error Please add support for your platform in build_config.h
#endif
diff --git a/intern/softbody/admmpd_api.cpp b/intern/softbody/admmpd_api.cpp
index 85d4718bf7f..a9699eb936b 100644
--- a/intern/softbody/admmpd_api.cpp
+++ b/intern/softbody/admmpd_api.cpp
@@ -31,32 +31,18 @@
#endif
#include "DNA_mesh_types.h" // Mesh
#include "DNA_meshdata_types.h" // MVert
+#include "DNA_modifier_types.h" // CollisionModifierData
#include "DNA_object_force_types.h" // Enums
#include "BKE_mesh.h" // BKE_mesh_free
#include "BKE_softbody.h" // BodyPoint
#include "BKE_deform.h" // BKE_defvert_find_index
+#include "BKE_modifier.h" // BKE_modifiers_findby_type
#include "MEM_guardedalloc.h"
#include <iostream>
#include <memory>
#include <algorithm>
-// Collision obstacles are cached until
-// solve(...) is called. If we are substepping,
-// the obstacle is interpolated from start to end.
-struct CollisionObstacle
-{
- Eigen::VectorXf x0, x1;
- std::vector<unsigned int> F;
- bool needs_sdf_recompute;
- void reset() {
- x0 = Eigen::VectorXf();
- x1 = Eigen::VectorXf();
- F.clear();
- needs_sdf_recompute = true;
- }
-};
-
struct ADMMPDInternalData
{
// Created in admmpd_update_mesh
@@ -66,7 +52,8 @@ struct ADMMPDInternalData
std::shared_ptr<admmpd::Options> options;
std::shared_ptr<admmpd::SolverData> data;
// Created in set_obstacles
- CollisionObstacle obs;
+ std::vector<Eigen::MatrixXd> obs_x0, obs_x1;
+ std::vector<Eigen::MatrixXi> obs_F;
};
@@ -104,6 +91,7 @@ static inline void options_from_object(
op->linsolver = std::max(0, std::min(LINSOLVER_NUM-1, sb->admmpd_linsolver));
op->strain_limit[0] = std::min(1.f, sb->admmpd_strainlimit_min);
op->strain_limit[1] = std::max(1.f, sb->admmpd_strainlimit_max);
+ op->lattice_subdiv = std::max(1,sb->admmpd_embed_res);
if (!skip_require_reset)
{
@@ -186,10 +174,8 @@ static inline int admmpd_init_with_lattice(ADMMPDInterfaceData *iface, Object *o
std::vector<unsigned int> f;
vecs_from_object(ob,vertexCos,v,f);
iface->idata->mesh = std::make_shared<admmpd::EmbeddedMesh>();
-
- admmpd::EmbeddedMesh* emb_msh = static_cast<admmpd::EmbeddedMesh*>(iface->idata->mesh.get());
- emb_msh->options.max_subdiv_levels = ob->soft->admmpd_embed_res;
bool success = iface->idata->mesh->create(
+ iface->idata->options.get(),
v.data(),
v.size()/3,
f.data(),
@@ -197,7 +183,7 @@ static inline int admmpd_init_with_lattice(ADMMPDInterfaceData *iface, Object *o
nullptr,
0);
- if (!success) {
+ if (!success) { // soft unknown fail
strcpy_error(iface, "EmbeddedMesh failed on creation");
return 0;
}
@@ -214,6 +200,7 @@ static inline int admmpd_init_as_cloth(ADMMPDInterfaceData *iface, Object *ob, f
iface->idata->mesh = std::make_shared<admmpd::TriangleMesh>();
bool success = iface->idata->mesh->create(
+ iface->idata->options.get(),
v.data(),
v.size()/3,
f.data(),
@@ -230,6 +217,53 @@ static inline int admmpd_init_as_cloth(ADMMPDInterfaceData *iface, Object *ob, f
return 1;
}
+void admmpd_compute_lattice(
+ int subdiv,
+ float *in_verts, int in_nv,
+ unsigned int *in_faces, int in_nf,
+ float **out_verts, int *out_nv,
+ unsigned int **out_tets, int *out_nt)
+{
+
+ admmpd::EmbeddedMesh emesh;
+ admmpd::Options opt;
+ opt.lattice_subdiv = subdiv;
+ bool success = emesh.create(
+ &opt,
+ in_verts, in_nv,
+ in_faces, in_nf,
+ nullptr,
+ 0);
+
+ if (!success) {
+ return;
+ }
+
+ const Eigen::MatrixXd &vt = *emesh.rest_prim_verts();
+ const Eigen::MatrixXi &t = *emesh.prims();
+ if (vt.rows()==0 || t.rows()==0) {
+ return;
+ }
+
+ *out_nv = vt.rows();
+ *out_verts = (float*)MEM_callocN(sizeof(float)*3*(vt.rows()), "ADMMPD_lattice_verts");
+ *out_nt = t.rows();
+ *out_tets = (unsigned int*)MEM_callocN(sizeof(unsigned int)*4*(t.rows()), "ADMMPD_lattice_tets");
+
+ for (int i=0; i<vt.rows(); ++i) {
+ (*out_verts)[i*3+0] = vt(i,0);
+ (*out_verts)[i*3+1] = vt(i,1);
+ (*out_verts)[i*3+2] = vt(i,2);
+ }
+
+ for (int i=0; i<t.rows(); ++i) {
+ (*out_tets)[i*4+0] = t(i,0);
+ (*out_tets)[i*4+1] = t(i,1);
+ (*out_tets)[i*4+2] = t(i,2);
+ (*out_tets)[i*4+3] = t(i,3);
+ }
+}
+
int admmpd_mesh_needs_update(ADMMPDInterfaceData *iface, Object *ob)
{
if (!iface) { return 0; }
@@ -244,6 +278,7 @@ int admmpd_mesh_needs_update(ADMMPDInterfaceData *iface, Object *ob)
// Mode or topology change?
int mode = ob->soft->admmpd_mesh_mode;
int mesh_type = iface->idata->mesh->type();
+
if (mode != mesh_type) { return 1; }
if (!iface->idata->mesh->rest_facet_verts()) { return 1; }
int nx = iface->idata->mesh->rest_facet_verts()->rows();
@@ -258,9 +293,15 @@ int admmpd_update_mesh(ADMMPDInterfaceData *iface, Object *ob, float (*vertexCos
if (!ob) { return 0; }
if (!ob->soft) { return 0; }
- if (!iface->idata)
+ if (!iface->idata) {
iface->idata = (ADMMPDInternalData*)MEM_callocN(sizeof(ADMMPDInternalData), "ADMMPD_idata");
+ }
+ if (!iface->idata->options) {
+ iface->idata->options = std::make_shared<admmpd::Options>();
+ }
+
+ options_from_object(iface,NULL,ob,iface->idata->options.get(),false);
int mode = ob->soft->admmpd_mesh_mode;
iface->idata->mesh.reset();
@@ -362,9 +403,13 @@ int admmpd_update_solver(ADMMPDInterfaceData *iface, Scene *sc, Object *ob, flo
if (!iface->idata->mesh) { return 0; }
// Reset options and data
- iface->idata->options = std::make_shared<admmpd::Options>();
+ if (!iface->idata->options) {
+ iface->idata->options = std::make_shared<admmpd::Options>();
+ }
iface->idata->data = std::make_shared<admmpd::SolverData>();
- iface->idata->obs.reset();
+ iface->idata->obs_x0.clear();
+ iface->idata->obs_x1.clear();
+ iface->idata->obs_F.clear();
admmpd::Options *op = iface->idata->options.get();
options_from_object(iface,sc,ob,op,false);
@@ -417,11 +462,18 @@ void admmpd_copy_to_object(ADMMPDInterfaceData *iface, Object *ob, float (*verte
if (ob && ob->soft) {
SoftBody *sb = ob->soft;
+
if (!sb->bpoint) {
if (!ob->soft->bpoint) {
sb->bpoint = (BodyPoint*)MEM_callocN(nx*sizeof(BodyPoint), "ADMMPD_bpoint");
}
+ sb->totpoint = nx;
+ sb->totspring = 0;
+ }
+ if (sb->totpoint != nx && sb->totpoint>0) {
+ MEM_freeN(sb->bpoint);
+ sb->bpoint = (BodyPoint*)MEM_callocN(nx*sizeof(BodyPoint), "ADMMPD_bpoint");
sb->totpoint = nx;
sb->totspring = 0;
}
@@ -454,66 +506,6 @@ void admmpd_copy_to_object(ADMMPDInterfaceData *iface, Object *ob, float (*verte
}
}
-void admmpd_update_obstacles(
- ADMMPDInterfaceData *iface,
- float *in_verts_0,
- float *in_verts_1,
- int nv,
- unsigned int *in_faces,
- int nf)
-{
- if (iface==NULL || in_verts_0==NULL || in_verts_1==NULL || in_faces==NULL) {
- return;
- }
- if (!iface->idata) { return; }
-
- if (nf==0 || nv==0) { return; }
- int nv3 = nv*3;
- int nf3 = nf*3;
- iface->idata->obs.needs_sdf_recompute = false;
-
- if (iface->idata->obs.x0.size()!=nv3) {
- iface->idata->obs.x0.resize(nv3);
- iface->idata->obs.needs_sdf_recompute = true;
- }
-
- if (iface->idata->obs.x1.size()!=nv3) {
- iface->idata->obs.x1.resize(nv3);
- iface->idata->obs.needs_sdf_recompute = true;
- }
-
- if (iface->idata->obs.F.size()!=nf3) {
- iface->idata->obs.F.resize(nf3);
- iface->idata->obs.needs_sdf_recompute = true;
- }
-
- for (int i=0; i<nv3; ++i) {
-
- // Change in x?
- if (!iface->idata->obs.needs_sdf_recompute) {
- if (std::abs(iface->idata->obs.x0[i]-in_verts_0[i])>1e-8 ||
- std::abs(iface->idata->obs.x1[i]-in_verts_1[i])>1e-8 ) {
- iface->idata->obs.needs_sdf_recompute = true;
- }
- }
-
- iface->idata->obs.x0[i] = in_verts_0[i];
- iface->idata->obs.x1[i] = in_verts_1[i];
- }
- for (int i=0; i<nf3; ++i) {
-
- // Change in f?
- if (!iface->idata->obs.needs_sdf_recompute) {
- if (iface->idata->obs.F[i] != in_faces[i]) {
- iface->idata->obs.needs_sdf_recompute = true;
- }
- }
-
- iface->idata->obs.F[i] = in_faces[i];
- }
-
-}
-
static inline void admmpd_update_goals(ADMMPDInterfaceData *iface, Object *ob, float (*vertexCos)[3])
{
if (!iface) { return; }
@@ -603,11 +595,18 @@ int admmpd_solve(ADMMPDInterfaceData *iface, Object *ob, float (*vertexCos)[3])
return 0;
}
- if (!iface->idata || !iface->idata->options || !iface->idata->data) {
+ if (!iface->idata || !iface->idata->options ||
+ !iface->idata->data || !iface->idata->mesh) {
strcpy_error(iface, "NULL internal data");
return 0;
}
+ std::string meshname(ob->id.name);
+
+ // Set to true if certain conditions should
+ // throw a warning flag.
+ bool return_warning = false;
+
// Change only options that do not cause a reset of the solver.
bool skip_solver_reset = true;
options_from_object(
@@ -617,6 +616,19 @@ int admmpd_solve(ADMMPDInterfaceData *iface, Object *ob, float (*vertexCos)[3])
iface->idata->options.get(),
skip_solver_reset);
+ // Disable self collision flag if the mesh does not support it.
+ if (iface->idata->options->self_collision &&
+ !iface->idata->mesh->self_collision_allowed()) {
+ // Special message if embedded, in which the mesh is not closed.
+ std::string err = "Cannot do self collisions on object "+meshname+" for selected mesh type";
+ if (iface->idata->mesh->type() == MESHTYPE_EMBEDDED) {
+ err = "Cannot do self collisions on object "+meshname+", mesh is not closed.";
+ }
+ strcpy_error(iface, err.c_str());
+ iface->idata->options->self_collision = false;
+ return_warning = true;
+ }
+
// Goals and self collision group can change
// between time steps. If the goal indices/weights change,
// it will trigger a refactorization in the solver.
@@ -625,12 +637,11 @@ int admmpd_solve(ADMMPDInterfaceData *iface, Object *ob, float (*vertexCos)[3])
// Obstacle collisions not yet implemented
// for cloth or tet mesh.
- bool had_set_obstacle_error = false;
if ((ob->soft->admmpd_mesh_mode == MESHTYPE_TET ||
ob->soft->admmpd_mesh_mode == MESHTYPE_TRIANGLE) &&
- iface->idata->obs.x0.size()>0)
+ iface->idata->obs_x0.size()>0)
{
- had_set_obstacle_error = true;
+ return_warning = true;
strcpy_error(iface, "Obstacle collision not yet available for selected mesh mode.");
}
@@ -640,47 +651,40 @@ int admmpd_solve(ADMMPDInterfaceData *iface, Object *ob, float (*vertexCos)[3])
// b) the obstacle positions have changed from the last frame
bool has_obstacles =
iface->idata->collision &&
- iface->idata->obs.x0.size() > 0 &&
- iface->idata->obs.F.size() > 0 &&
- iface->idata->obs.x0.size()==iface->idata->obs.x1.size();
- bool lerp_obstacles =
- has_obstacles &&
- iface->idata->options->substeps>1 &&
- (iface->idata->obs.x0-iface->idata->obs.x1).lpNorm<Eigen::Infinity>()>1e-6;
-
- if (has_obstacles && iface->idata->obs.needs_sdf_recompute && !lerp_obstacles) {
+ iface->idata->obs_x0.size() > 0 &&
+ iface->idata->obs_x1.size() > 0 &&
+ iface->idata->obs_x0[0].size()==iface->idata->obs_x1[0].size();
+
+ int substeps = std::max(1,iface->idata->options->substeps);
+ int n_obs = iface->idata->obs_x0.size();
+ if (has_obstacles && substeps == 1) { // no lerp necessary
std::string set_obs_error = "";
if (!iface->idata->collision->set_obstacles(
- iface->idata->obs.x0.data(),
- iface->idata->obs.x1.data(),
- iface->idata->obs.x0.size()/3,
- iface->idata->obs.F.data(),
- iface->idata->obs.F.size()/3,
+ iface->idata->obs_x0, iface->idata->obs_x1, iface->idata->obs_F,
&set_obs_error)) {
strcpy_error(iface, set_obs_error.c_str());
- had_set_obstacle_error = true;
+ return_warning = true;
}
}
try
{
- Eigen::VectorXf obs_x1; // used if substeps > 1
- int substeps = std::max(1,iface->idata->options->substeps);
+ std::vector<Eigen::MatrixXd> obs_x1_t;
for (int i=0; i<substeps; ++i) {
- if (lerp_obstacles) {
+ // Interpolate obstacles
+ if (has_obstacles && substeps>1) {
float t = float(i)/float(substeps-1);
- obs_x1 = (1.f-t)*iface->idata->obs.x0 + t*iface->idata->obs.x1;
+ obs_x1_t.resize(n_obs);
+ for (int j=0; j<n_obs; ++j) {
+ obs_x1_t[j] = (1.f-t)*iface->idata->obs_x0[j] + t*iface->idata->obs_x1[j];
+ }
std::string set_obs_error = "";
- if (iface->idata->collision->set_obstacles(
- iface->idata->obs.x0.data(),
- obs_x1.data(),
- iface->idata->obs.x0.size()/3,
- iface->idata->obs.F.data(),
- iface->idata->obs.F.size()/3,
+ if (!iface->idata->collision->set_obstacles(
+ iface->idata->obs_x0, iface->idata->obs_x1, iface->idata->obs_F,
&set_obs_error)) {
strcpy_error(iface, set_obs_error.c_str());
- had_set_obstacle_error = true;
+ return_warning = true;
}
}
@@ -699,8 +703,7 @@ int admmpd_solve(ADMMPDInterfaceData *iface, Object *ob, float (*vertexCos)[3])
return 0;
}
- if (had_set_obstacle_error) {
- // Return warning (-1).
+ if (return_warning) {
// We've already copied the error message.
return -1;
}
@@ -708,6 +711,59 @@ int admmpd_solve(ADMMPDInterfaceData *iface, Object *ob, float (*vertexCos)[3])
return 1;
}
+void admmpd_update_obstacles(ADMMPDInterfaceData *iface, Object **obstacles, int numobjects)
+{
+ // Because substepping may occur, we'll buffer the start and end states
+ // of the obstacles. They will not be copied over to the collision pointer
+ // until solve(), depending on the number of substeps, in which case
+ // they are LERP'd
+ iface->idata->obs_x0.clear();
+ iface->idata->obs_x1.clear();
+ iface->idata->obs_F.clear();
+ if (!iface) { return; }
+ if (!iface->idata) { return; }
+ if (!obstacles || numobjects==0) { return; }
+
+ for (int i = 0; i < numobjects; ++i) {
+ Object *ob = obstacles[i];
+ if (!ob) {
+ continue; // uh?
+ }
+ if (ob->type != OB_MESH) {
+ continue; // is not a mesh type
+ }
+ if (!ob->pd || !ob->pd->deflect) {
+ continue; // is a non-collider
+ }
+ if (strcmp(ob->id.name,iface->name)==0) {
+ continue; // skip self
+ }
+
+ CollisionModifierData *cmd = (CollisionModifierData *)BKE_modifiers_findby_type(
+ ob, eModifierType_Collision);
+ if (!cmd) {
+ continue;
+ }
+
+ int idx = iface->idata->obs_x0.size();
+ iface->idata->obs_x0.emplace_back(Eigen::MatrixXd(cmd->mvert_num,3));
+ iface->idata->obs_x1.emplace_back(Eigen::MatrixXd(cmd->mvert_num,3));
+ iface->idata->obs_F.emplace_back(Eigen::MatrixXi(cmd->tri_num,3));
+
+ for (int j=0; j<cmd->mvert_num; ++j) {
+ for (int k=0; k<3; ++k) {
+ iface->idata->obs_x0[idx](j,k) = cmd->x[j].co[k];
+ iface->idata->obs_x1[idx](j,k) = cmd->xnew[j].co[k];
+ }
+ }
+
+ for (int j=0; j<cmd->tri_num; ++j) {
+ for (int k=0; k<3; ++k) {
+ iface->idata->obs_F[idx](j,k) = cmd->tri[j].tri[k];
+ }
+ }
+ }
+}
#ifdef WITH_TETGEN
@@ -864,6 +920,7 @@ static inline int admmpd_init_with_tetgen(ADMMPDInterfaceData *iface, Object *ob
iface->idata->mesh = std::make_shared<admmpd::TetMesh>();
bool success = iface->idata->mesh->create(
+ iface->idata->options.get(),
verts.data(),
nv,
faces.data(),
diff --git a/intern/softbody/admmpd_api.h b/intern/softbody/admmpd_api.h
index 18b0b8e3389..1055a5c9e7f 100644
--- a/intern/softbody/admmpd_api.h
+++ b/intern/softbody/admmpd_api.h
@@ -32,51 +32,72 @@ extern "C" {
#include "DNA_scene_types.h"
typedef struct ADMMPDInterfaceData {
- char last_error[256]; // last error message
- struct ADMMPDInternalData *idata; // internal data
+ /* So that ADMMPD data can be stored in a linked list. */
+ struct ADMMPDInterfaceData *next, *prev;
+ /* The name of the object that uses this data. */
+ char name[MAX_ID_NAME];
+ /* If API returns 0, error stored here. */
+ char last_error[256];
+ /* internal data is NULL until update_mesh or update_solver. */
+ struct ADMMPDInternalData *idata;
} ADMMPDInterfaceData;
-// Frees ADMMPDInternalData
+/* Frees ADMMPDInternalData */
void admmpd_dealloc(ADMMPDInterfaceData*);
-// Test if the mesh topology has changed in a way that requires re-initialization.
-// Returns 0 (no update needed) or 1 (needs update)
+/* Standalone function to compute embedding lattice
+* but without the embedding info (for visual debugging) */
+void admmpd_compute_lattice(
+ int subdiv,
+ float *in_verts, int in_nv,
+ unsigned int *in_faces, int in_nf,
+ float **out_verts, int *out_nv,
+ unsigned int **out_tets, int *out_nt);
+
+/* Test if the mesh topology has changed in a way that requires re-initialization.
+* Returns 0 (no update needed) or 1 (needs update) */
int admmpd_mesh_needs_update(ADMMPDInterfaceData*, Object*);
-// Initialize the mesh.
-// The SoftBody object's (ob->soft) bpoint array is also updated.
-// Returns 1 on success, 0 on failure, -1 on warning
+/* Initialize the mesh.
+* The SoftBody object's (ob->soft) bpoint array is also updated.
+* Returns 1 on success, 0 on failure, -1 on warning */
int admmpd_update_mesh(ADMMPDInterfaceData*, Object*, float (*vertexCos)[3]);
-// Test if certain parameter changes require re-initialization.
-// Returns 0 (no update needed) or 1 (needs update)
+/* Test if certain parameter changes require re-initialization.
+* Returns 0 (no update needed) or 1 (needs update) */
int admmpd_solver_needs_update(ADMMPDInterfaceData*, Scene*, Object*);
-// Initialize solver variables.
-// Returns 1 on success, 0 on failure, -1 on warning
+/* Initialize solver variables.
+* Returns 1 on success, 0 on failure, -1 on warning */
int admmpd_update_solver(ADMMPDInterfaceData*, Scene*, Object*, float (*vertexCos)[3]);
-// Copies BodyPoint data (from SoftBody)
-// to internal vertex position and velocity
+/* Copies BodyPoint data (from SoftBody)
+* to internal vertex position and velocity */
void admmpd_copy_from_object(ADMMPDInterfaceData*, Object*);
-// Copies ADMM-PD data to SoftBody::bpoint and vertexCos.
-// If vertexCos is NULL, it is ignored.
+/* Copies ADMM-PD data to SoftBody::bpoint and vertexCos.
+* If vertexCos is NULL, it is ignored. */
void admmpd_copy_to_object(ADMMPDInterfaceData*, Object*, float (*vertexCos)[3]);
-// Sets the obstacle data for collisions.
-// Update obstacles has a different interface because of the
-// complexity of grabbing obstacle mesh data. We'll leave that in softbody.c
+/* Sets the obstacle data for collisions. */
void admmpd_update_obstacles(
ADMMPDInterfaceData*,
- float *in_verts_0,
- float *in_verts_1,
- int nv,
- unsigned int *in_faces,
- int nf);
-
-// Performs a time step. Object and vertexCos are not changed.
-// Returns 1 on success, 0 on failure, -1 on warning
+ Object**,
+ int numobjects);
+
+/* Sets the obstacle data for collisions.
+* Update obstacles has a different interface because of the
+* complexity of grabbing obstacle mesh data. We'll leave that in softbody.c */
+//void admmpd_update_obstacles(
+// ADMMPDInterfaceData*,
+// float *in_verts_0,
+// float *in_verts_1,
+// int nv,
+// unsigned int *in_faces,
+// int nf);
+
+/* Performs a time step. Object and vertexCos are not changed.
+* Returns 1 on success, 0 on failure, -1 on warning */
int admmpd_solve(ADMMPDInterfaceData*, Object*, float (*vertexCos)[3]);
#ifdef __cplusplus